更新
This commit is contained in:
parent
b5ac7e8f32
commit
7b4e41efc4
@ -5,22 +5,101 @@ use think\facade\Request;
|
||||
use think\facade\Log;
|
||||
use think\facade\Cache;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
use app\index\model\User;
|
||||
use app\index\model\AdminConfig;
|
||||
|
||||
class WechatController extends BaseController
|
||||
{
|
||||
/**
|
||||
* 测试接口是否正常工作
|
||||
*/
|
||||
public function test()
|
||||
{
|
||||
try {
|
||||
// 设置响应头
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$data = [
|
||||
'time' => date('Y-m-d H:i:s'),
|
||||
'status' => 'ok',
|
||||
'server' => [
|
||||
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
|
||||
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
|
||||
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
|
||||
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
]
|
||||
];
|
||||
|
||||
// 记录详细日志
|
||||
Log::info('接口测试 - 请求信息:' . json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return json($data, JSON_UNESCAPED_UNICODE);
|
||||
} catch (\Exception $e) {
|
||||
$error = [
|
||||
'error' => $e->getMessage(),
|
||||
'time' => date('Y-m-d H:i:s')
|
||||
];
|
||||
Log::error('接口测试错误:' . json_encode($error, JSON_UNESCAPED_UNICODE));
|
||||
return json($error, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// 检查请求方法
|
||||
if (Request::method() == 'GET') {
|
||||
// 首次验证服务器地址的有效性
|
||||
$this->checkSignature();
|
||||
} elseif (Request::method() == 'POST') {
|
||||
// 接收消息并回复
|
||||
$response = $this->receiveMessage();
|
||||
// 直接输出回复的XML字符串
|
||||
echo $response;
|
||||
try {
|
||||
// 设置响应头
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
// 记录原始请求信息
|
||||
$requestInfo = [
|
||||
'time' => date('Y-m-d H:i:s'),
|
||||
'method' => Request::method(),
|
||||
'url' => Request::url(true),
|
||||
'ip' => Request::ip(),
|
||||
'params' => Request::param(),
|
||||
'headers' => getallheaders(),
|
||||
'server' => [
|
||||
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
|
||||
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
|
||||
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
|
||||
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
'QUERY_STRING' => $_SERVER['QUERY_STRING'] ?? '',
|
||||
'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
'HTTP_REFERER' => $_SERVER['HTTP_REFERER'] ?? '',
|
||||
]
|
||||
];
|
||||
|
||||
Log::info('微信接口访问请求信息:' . json_encode($requestInfo, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 获取原始数据
|
||||
$rawData = file_get_contents("php://input");
|
||||
if (!empty($rawData)) {
|
||||
$rawData = mb_convert_encoding($rawData, 'UTF-8', 'UTF-8,GBK,GB2312');
|
||||
Log::info('微信接口原始数据:' . $rawData);
|
||||
}
|
||||
|
||||
// 检查请求方法
|
||||
if (Request::method() == 'GET') {
|
||||
Log::info('微信接口:GET请求,进行签名验证');
|
||||
// 首次验证服务器地址的有效性
|
||||
$this->checkSignature();
|
||||
} elseif (Request::method() == 'POST') {
|
||||
Log::info('微信接口:POST请求,处理消息');
|
||||
// 接收消息并回复
|
||||
$response = $this->receiveMessage();
|
||||
// 直接输出回复的XML字符串
|
||||
echo $response;
|
||||
exit;
|
||||
} else {
|
||||
Log::error('微信接口:不支持的请求方法 - ' . Request::method());
|
||||
echo '';
|
||||
exit;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('微信接口错误:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
// 返回空字符串,避免微信服务器重试
|
||||
echo '';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@ -28,18 +107,62 @@ class WechatController extends BaseController
|
||||
// 验证签名
|
||||
protected function checkSignature()
|
||||
{
|
||||
$signature = Request::get('signature');
|
||||
$timestamp = Request::get('timestamp');
|
||||
$nonce = Request::get('nonce');
|
||||
$echostr = Request::get('echostr');
|
||||
$token = AdminConfig::where('config_name', 'wechat_token')->value('config_value');
|
||||
$tmpArr = array($token, $timestamp, $nonce);
|
||||
sort($tmpArr, SORT_STRING);
|
||||
$tmpStr = implode($tmpArr);
|
||||
$tmpStr = sha1($tmpStr);
|
||||
try {
|
||||
$signature = Request::get('signature');
|
||||
$timestamp = Request::get('timestamp');
|
||||
$nonce = Request::get('nonce');
|
||||
$echostr = Request::get('echostr');
|
||||
|
||||
if ($tmpStr == $signature) {
|
||||
echo $echostr;
|
||||
$debugInfo = [
|
||||
'signature' => $signature,
|
||||
'timestamp' => $timestamp,
|
||||
'nonce' => $nonce,
|
||||
'echostr' => $echostr,
|
||||
'url' => Request::url(true),
|
||||
'time' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
Log::info('微信验证参数:', $debugInfo);
|
||||
|
||||
if (empty($signature) || empty($timestamp) || empty($nonce)) {
|
||||
Log::error('微信验证参数缺失', $debugInfo);
|
||||
exit;
|
||||
}
|
||||
|
||||
$token = AdminConfig::where('config_name', 'wechat_token')->value('config_value');
|
||||
if (empty($token)) {
|
||||
Log::error('微信token未配置');
|
||||
exit;
|
||||
}
|
||||
|
||||
Log::info('微信token:' . $token);
|
||||
|
||||
$tmpArr = array($token, $timestamp, $nonce);
|
||||
sort($tmpArr, SORT_STRING);
|
||||
$tmpStr = implode($tmpArr);
|
||||
$tmpStr = sha1($tmpStr);
|
||||
|
||||
$verifyInfo = [
|
||||
'tmpStr' => $tmpStr,
|
||||
'signature' => $signature,
|
||||
'token' => $token,
|
||||
'timestamp' => $timestamp,
|
||||
'nonce' => $nonce
|
||||
];
|
||||
|
||||
Log::info('签名验证:', $verifyInfo);
|
||||
|
||||
if ($tmpStr == $signature) {
|
||||
Log::info('微信签名验证成功');
|
||||
echo $echostr;
|
||||
exit;
|
||||
} else {
|
||||
Log::error('微信签名验证失败', $verifyInfo);
|
||||
exit;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('微信验证签名错误:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@ -47,45 +170,128 @@ class WechatController extends BaseController
|
||||
// 接收消息
|
||||
protected function receiveMessage()
|
||||
{
|
||||
$postStr = file_get_contents("php://input");
|
||||
if (empty($postStr)) {
|
||||
return '';
|
||||
try {
|
||||
$postStr = file_get_contents("php://input");
|
||||
if (empty($postStr)) {
|
||||
Log::error('微信消息:接收数据为空');
|
||||
return '';
|
||||
}
|
||||
|
||||
// 转换编码
|
||||
$postStr = mb_convert_encoding($postStr, 'UTF-8', 'UTF-8,GBK,GB2312');
|
||||
Log::info('微信消息:' . $postStr);
|
||||
|
||||
libxml_disable_entity_loader(true);
|
||||
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if ($postObj === false) {
|
||||
Log::error('微信消息:XML解析失败');
|
||||
return '';
|
||||
}
|
||||
|
||||
// 检查消息类型
|
||||
$msgType = strtolower((string) $postObj->MsgType);
|
||||
Log::info('微信消息类型:' . $msgType);
|
||||
|
||||
// 处理事件消息
|
||||
if ($msgType == 'event') {
|
||||
$event = strtolower((string) $postObj->Event);
|
||||
Log::info('微信事件类型:' . $event);
|
||||
|
||||
// 处理扫码事件和关注事件
|
||||
if ($event == 'scan' || $event == 'subscribe') {
|
||||
$scene_str = trim((string) $postObj->EventKey);
|
||||
// 如果是关注事件,需要去掉前缀 'qrscene_'
|
||||
if ($event == 'subscribe' && strpos($scene_str, 'qrscene_') === 0) {
|
||||
$scene_str = substr($scene_str, 8);
|
||||
}
|
||||
|
||||
$fromUsername = trim((string) $postObj->FromUserName);
|
||||
$toUsername = trim((string) $postObj->ToUserName);
|
||||
$ticket = (string) $postObj->Ticket;
|
||||
|
||||
Log::info('微信扫码/关注事件', [
|
||||
'event' => $event,
|
||||
'scene_str' => $scene_str,
|
||||
'fromUsername' => $fromUsername,
|
||||
'toUsername' => $toUsername,
|
||||
'ticket' => $ticket,
|
||||
'time' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// 创建票据保存目录
|
||||
$upload_dir = 'public/storage/uploads/ticket/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
Log::info('创建票据保存目录:' . $upload_dir);
|
||||
}
|
||||
|
||||
// 保存扫码数据
|
||||
$data = [
|
||||
'openid' => $fromUsername,
|
||||
'scene_str' => $scene_str,
|
||||
'ticket' => $ticket,
|
||||
'scan_time' => time(),
|
||||
'event' => $event
|
||||
];
|
||||
|
||||
$content = json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
$file = $upload_dir . $scene_str . "_" . $ticket . ".json";
|
||||
file_put_contents($file, $content);
|
||||
Log::info('保存扫码数据到文件:' . $file);
|
||||
|
||||
// 获取用户信息
|
||||
try {
|
||||
$accessToken = $this->getGZHAccessToken();
|
||||
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$accessToken}&openid={$fromUsername}&lang=zh_CN";
|
||||
$client = new Client(['verify' => false]);
|
||||
$response = $client->get($url);
|
||||
$userInfo = json_decode($response->getBody(), true);
|
||||
|
||||
Log::info('获取用户信息结果:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
if (isset($userInfo['openid'])) {
|
||||
// 保存用户信息到数据库
|
||||
$user = User::where('openid', $fromUsername)->find();
|
||||
if (!$user) {
|
||||
$user = new User;
|
||||
$user->openid = $fromUsername;
|
||||
$user->name = $userInfo['nickname'] ?? '';
|
||||
$user->avatar = $userInfo['headimgurl'] ?? '';
|
||||
$user->save();
|
||||
Log::info('创建新用户', ['user' => $user->toArray()]);
|
||||
} else {
|
||||
// 更新用户信息
|
||||
$user->name = $userInfo['nickname'] ?? $user->name;
|
||||
$user->avatar = $userInfo['headimgurl'] ?? $user->avatar;
|
||||
$user->save();
|
||||
Log::info('更新用户信息', ['user' => $user->toArray()]);
|
||||
}
|
||||
|
||||
// 更新票据文件中的用户信息
|
||||
$data['user_info'] = [
|
||||
'uid' => $user->uid,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'openid' => $user->openid
|
||||
];
|
||||
file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
Log::info('更新票据文件中的用户信息');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('获取用户信息失败:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
}
|
||||
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} catch (\Exception $e) {
|
||||
Log::error('处理微信消息错误:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
return 'success';
|
||||
}
|
||||
|
||||
libxml_disable_entity_loader(true);
|
||||
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
Log::write($postObj);
|
||||
// 检查消息类型
|
||||
$msgType = strtolower((string) $postObj->MsgType);
|
||||
if ($msgType == 'text') {
|
||||
// 提取消息内容
|
||||
$fromUsername = (string) $postObj->FromUserName; // 微信用户openid
|
||||
$toUsername = (string) $postObj->ToUserName; // 公众号id
|
||||
$keyword = trim((string) $postObj->Content);
|
||||
|
||||
// 构造自动回复的文本消息
|
||||
$time = time();
|
||||
$textTpl = "<xml>
|
||||
<ToUserName><![CDATA[%s]]></ToUserName>
|
||||
<FromUserName><![CDATA[%s]]></FromUserName>
|
||||
<CreateTime>%s</CreateTime>
|
||||
<MsgType><![CDATA[text]]></MsgType>
|
||||
<Content><![CDATA[%s]]></Content>
|
||||
<FuncFlag>0</FuncFlag>
|
||||
</xml>";
|
||||
|
||||
|
||||
$responseContent = "消息标题";
|
||||
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $responseContent);
|
||||
// 假设已经确定要发送小程序卡片消息
|
||||
$this->sendMiniProgramCard((string) $postObj->FromUserName);
|
||||
|
||||
return $resultStr;
|
||||
}
|
||||
// 如果需要处理其他类型的消息,可以在这里添加相应的逻辑
|
||||
|
||||
// 如果不是文本消息,可以返回一个空字符串或错误消息
|
||||
return '';
|
||||
}
|
||||
|
||||
// 发送小程序卡片消息的方法
|
||||
@ -165,19 +371,113 @@ class WechatController extends BaseController
|
||||
public function getLoginTicket()
|
||||
{
|
||||
try {
|
||||
Log::info('开始获取微信登录二维码');
|
||||
|
||||
// 获取access_token
|
||||
$access_token = $this->getGZHAccessToken();
|
||||
Log::info('获取access_token成功:' . $access_token);
|
||||
|
||||
// 构建请求URL - 使用正确的接口生成临时二维码
|
||||
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}";
|
||||
|
||||
// 生成唯一场景值
|
||||
$scene_str = md5(uniqid() . time());
|
||||
Log::info('生成场景值:' . $scene_str);
|
||||
|
||||
// 准备请求数据 - 生成临时二维码,有效期5分钟
|
||||
$postData = json_encode([
|
||||
'expire_seconds' => 300, // 5分钟有效期
|
||||
'action_name' => 'QR_STR_SCENE',
|
||||
'action_info' => [
|
||||
'scene' => [
|
||||
'scene_str' => md5(uniqid() . time()) // 生成唯一场景值
|
||||
'scene_str' => $scene_str
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
// 发送请求获取ticket
|
||||
$client = new Client(['verify' => false]);
|
||||
$response = $client->post($url, [
|
||||
'body' => $postData,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
$result = json_decode($response->getBody(), true);
|
||||
Log::info('微信返回结果:' . json_encode($result, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
if (isset($result['errcode']) && $result['errcode'] != 0) {
|
||||
Log::error('获取二维码失败:' . $result['errmsg']);
|
||||
return json(['code' => 1, 'msg' => '获取二维码失败:' . $result['errmsg']]);
|
||||
}
|
||||
|
||||
// 使用ticket获取二维码图片URL
|
||||
$ticket = urlencode($result['ticket']);
|
||||
$qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$ticket}";
|
||||
|
||||
// 将场景值保存到缓存中,用于后续验证
|
||||
Cache::set('wx_login_scene_' . $result['ticket'], [
|
||||
'scene_str' => $scene_str,
|
||||
'create_time' => time(),
|
||||
'expire_time' => time() + 300
|
||||
], 300);
|
||||
|
||||
Log::info('二维码生成成功', [
|
||||
'ticket' => $result['ticket'],
|
||||
'scene_str' => $scene_str,
|
||||
'expire_time' => time() + 300
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 0,
|
||||
'msg' => '获取二维码成功',
|
||||
'data' => [
|
||||
'ticket' => $result['ticket'],
|
||||
'expire_seconds' => $result['expire_seconds'],
|
||||
'url' => $qrcodeUrl,
|
||||
'scene_str' => $scene_str
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('获取微信登录二维码失败:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
return json(['code' => 1, 'msg' => '获取二维码失败:' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新生成二维码
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function reGenerateQrcode()
|
||||
{
|
||||
try {
|
||||
$scene_str = Request::post('scene_str');
|
||||
if (empty($scene_str)) {
|
||||
return json(['code' => 1, 'msg' => '参数错误']);
|
||||
}
|
||||
|
||||
// 清除旧的缓存
|
||||
Cache::delete('wx_login_scene_' . $scene_str);
|
||||
|
||||
// 获取access_token
|
||||
$access_token = $this->getGZHAccessToken();
|
||||
|
||||
// 构建请求URL
|
||||
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}";
|
||||
|
||||
// 生成新的场景值
|
||||
$new_scene_str = md5(uniqid() . time());
|
||||
|
||||
// 准备请求数据
|
||||
$postData = json_encode([
|
||||
'expire_seconds' => 300,
|
||||
'action_name' => 'QR_STR_SCENE',
|
||||
'action_info' => [
|
||||
'scene' => [
|
||||
'scene_str' => $new_scene_str
|
||||
]
|
||||
]
|
||||
]);
|
||||
@ -201,9 +501,9 @@ class WechatController extends BaseController
|
||||
$ticket = urlencode($result['ticket']);
|
||||
$qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$ticket}";
|
||||
|
||||
// 将场景值保存到缓存中,用于后续验证
|
||||
Cache::set('wx_login_scene_' . $result['ticket'], [
|
||||
'scene_str' => $postData['action_info']['scene']['scene_str'],
|
||||
// 将新的场景值保存到缓存中
|
||||
Cache::set('wx_login_scene_' . $new_scene_str, [
|
||||
'scene_str' => $new_scene_str,
|
||||
'create_time' => time(),
|
||||
'expire_time' => time() + 300
|
||||
], 300);
|
||||
@ -215,13 +515,176 @@ class WechatController extends BaseController
|
||||
'ticket' => $result['ticket'],
|
||||
'expire_seconds' => $result['expire_seconds'],
|
||||
'url' => $qrcodeUrl,
|
||||
'scene_str' => $postData['action_info']['scene']['scene_str']
|
||||
'scene_str' => $new_scene_str
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('获取微信登录二维码失败:' . $e->getMessage());
|
||||
return json(['code' => 1, 'msg' => '获取二维码失败:' . $e->getMessage()]);
|
||||
Log::error('重新生成二维码失败:' . $e->getMessage());
|
||||
return json(['code' => 1, 'msg' => '重新生成二维码失败:' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查微信扫码登录状态
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function checkLoginStatus()
|
||||
{
|
||||
try {
|
||||
$scene_str = Request::post('scene_str');
|
||||
$ticket = Request::post('ticket');
|
||||
|
||||
Log::info('检查登录状态', [
|
||||
'scene_str' => $scene_str,
|
||||
'ticket' => $ticket,
|
||||
'time' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
if (empty($scene_str) || empty($ticket)) {
|
||||
Log::warning('检查登录状态参数错误', [
|
||||
'scene_str' => $scene_str,
|
||||
'ticket' => $ticket
|
||||
]);
|
||||
return json(['code' => 0, 'msg' => '参数错误']);
|
||||
}
|
||||
|
||||
// 检查票据文件
|
||||
$file = 'public/storage/uploads/ticket/' . $scene_str . "_" . $ticket . ".json";
|
||||
Log::info('检查票据文件:' . $file);
|
||||
|
||||
if (file_exists($file)) {
|
||||
$loginData = json_decode(file_get_contents($file), true);
|
||||
Log::info('票据文件内容:' . json_encode($loginData, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
if ($loginData) {
|
||||
// 检查是否包含用户信息
|
||||
if (isset($loginData['user_info'])) {
|
||||
Log::info('用户已扫码登录', [
|
||||
'user_info' => $loginData['user_info']
|
||||
]);
|
||||
|
||||
// 设置登录session
|
||||
session('user_id', $loginData['user_info']['uid']);
|
||||
session('user_info', $loginData['user_info']);
|
||||
session('openid', $loginData['user_info']['openid']);
|
||||
|
||||
// 删除临时文件
|
||||
unlink($file);
|
||||
|
||||
return json(['code' => 1, 'msg' => '登录成功']);
|
||||
} else {
|
||||
Log::info('等待获取用户信息');
|
||||
return json(['code' => 0, 'msg' => '正在获取用户信息,请稍候...']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('等待扫码');
|
||||
return json(['code' => 0, 'msg' => '等待扫码']);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('检查登录状态失败:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
return json(['code' => 0, 'msg' => '系统错误']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据openid获取用户信息
|
||||
* @param string $openid
|
||||
* @return array|null
|
||||
*/
|
||||
private function getUserInfoByOpenid($openid)
|
||||
{
|
||||
try {
|
||||
// 这里需要根据你的用户表结构来实现
|
||||
// 示例:从用户表中查询openid对应的用户信息
|
||||
$user = User::where('openid', $openid)->find();
|
||||
if ($user) {
|
||||
return $user->toArray();
|
||||
}
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('获取用户信息失败:' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试微信服务器访问
|
||||
*/
|
||||
public function testWechat()
|
||||
{
|
||||
try {
|
||||
// 记录所有请求信息
|
||||
$requestInfo = [
|
||||
'time' => date('Y-m-d H:i:s'),
|
||||
'method' => Request::method(),
|
||||
'url' => Request::url(true),
|
||||
'ip' => Request::ip(),
|
||||
'params' => Request::param(),
|
||||
'headers' => getallheaders(),
|
||||
'server' => [
|
||||
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
|
||||
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
|
||||
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
|
||||
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
'QUERY_STRING' => $_SERVER['QUERY_STRING'] ?? '',
|
||||
'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
'HTTP_REFERER' => $_SERVER['HTTP_REFERER'] ?? '',
|
||||
]
|
||||
];
|
||||
|
||||
Log::info('微信测试接口访问:' . json_encode($requestInfo, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 获取原始数据
|
||||
$rawData = file_get_contents("php://input");
|
||||
if (!empty($rawData)) {
|
||||
$rawData = mb_convert_encoding($rawData, 'UTF-8', 'UTF-8,GBK,GB2312');
|
||||
Log::info('微信测试接口原始数据:' . $rawData);
|
||||
}
|
||||
|
||||
// 如果是GET请求,进行签名验证
|
||||
if (Request::method() == 'GET') {
|
||||
$signature = Request::get('signature');
|
||||
$timestamp = Request::get('timestamp');
|
||||
$nonce = Request::get('nonce');
|
||||
$echostr = Request::get('echostr');
|
||||
|
||||
Log::info('微信测试接口验证参数:', [
|
||||
'signature' => $signature,
|
||||
'timestamp' => $timestamp,
|
||||
'nonce' => $nonce,
|
||||
'echostr' => $echostr
|
||||
]);
|
||||
|
||||
if (!empty($signature) && !empty($timestamp) && !empty($nonce)) {
|
||||
$token = AdminConfig::where('config_name', 'wechat_token')->value('config_value');
|
||||
if (empty($token)) {
|
||||
Log::error('微信token未配置');
|
||||
return 'token not configured';
|
||||
}
|
||||
|
||||
$tmpArr = array($token, $timestamp, $nonce);
|
||||
sort($tmpArr, SORT_STRING);
|
||||
$tmpStr = implode($tmpArr);
|
||||
$tmpStr = sha1($tmpStr);
|
||||
|
||||
if ($tmpStr == $signature) {
|
||||
Log::info('微信测试接口验证成功');
|
||||
return $echostr;
|
||||
} else {
|
||||
Log::error('微信测试接口验证失败');
|
||||
return 'signature verification failed';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} catch (\Exception $e) {
|
||||
Log::error('微信测试接口错误:' . $e->getMessage());
|
||||
Log::error('错误堆栈:' . $e->getTraceAsString());
|
||||
return 'error';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,11 +112,12 @@
|
||||
.wechat-login {
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.wechat-login img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
@ -129,6 +130,30 @@
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#qrcode-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#qrcode-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#qrcode-loading .layui-icon {
|
||||
font-size: 40px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
#qrcode-loading p {
|
||||
margin-top: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.layui-input-inline {
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
@ -144,6 +169,33 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
/* margin: 50px auto; */
|
||||
text-align: center;
|
||||
}
|
||||
.qrcode-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.qrcode-container img {
|
||||
max-width: 200px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.qrcode-container p {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.status {
|
||||
color: #666;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.error {
|
||||
color: #ff4d4f;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -220,8 +272,15 @@
|
||||
</div> -->
|
||||
<div class="layui-tab-item" id="wechat">
|
||||
<div class="wechat-login">
|
||||
<img src="" alt="微信登录" class="layui-img">
|
||||
<p>点击使用微信登录</p>
|
||||
<div class="container">
|
||||
<h2>微信扫码登录</h2>
|
||||
<div class="qrcode-container">
|
||||
<img id="qrcode" src="" alt="微信登录二维码" onclick="reGenerateQrcode()">
|
||||
<p>点击二维码可刷新</p>
|
||||
</div>
|
||||
<div id="status" class="status">正在加载二维码...</div>
|
||||
<div id="error" class="error"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -232,6 +291,131 @@
|
||||
var form = layui.form;
|
||||
var element = layui.element;
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 微信登录相关变量
|
||||
var checkLoginTimer = null;
|
||||
var currentSceneStr = '';
|
||||
var currentTicket = '';
|
||||
var qrcodeExpireTime = 0; // 二维码过期时间
|
||||
|
||||
// 获取微信登录二维码
|
||||
function getQrcode() {
|
||||
$.ajax({
|
||||
url: '/index/wechat/getLoginTicket',
|
||||
type: 'GET',
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
$('#qrcode').attr('src', res.data.url);
|
||||
currentSceneStr = res.data.scene_str;
|
||||
currentTicket = res.data.ticket;
|
||||
// 设置二维码过期时间(5分钟)
|
||||
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
|
||||
$('#status').text('等待扫码...');
|
||||
$('#error').text('');
|
||||
// 开始检查登录状态
|
||||
startCheckLogin();
|
||||
} else {
|
||||
$('#error').text('获取二维码失败:' + res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('获取二维码失败,请刷新页面重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重新生成二维码
|
||||
function reGenerateQrcode() {
|
||||
if (!currentSceneStr) {
|
||||
getQrcode();
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除之前的定时器
|
||||
if (checkLoginTimer) {
|
||||
clearInterval(checkLoginTimer);
|
||||
checkLoginTimer = null;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/index/wechat/reGenerateQrcode',
|
||||
type: 'POST',
|
||||
data: {
|
||||
scene_str: currentSceneStr
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
$('#qrcode').attr('src', res.data.url);
|
||||
currentSceneStr = res.data.scene_str;
|
||||
currentTicket = res.data.ticket;
|
||||
// 设置新的二维码过期时间(5分钟)
|
||||
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
|
||||
$('#status').text('等待扫码...');
|
||||
$('#error').text('');
|
||||
// 开始检查登录状态
|
||||
startCheckLogin();
|
||||
} else {
|
||||
$('#error').text('刷新二维码失败:' + res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('刷新二维码失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 开始检查登录状态
|
||||
function startCheckLogin() {
|
||||
if (checkLoginTimer) {
|
||||
clearInterval(checkLoginTimer);
|
||||
}
|
||||
|
||||
checkLoginTimer = setInterval(function() {
|
||||
// 检查二维码是否过期
|
||||
if (new Date().getTime() > qrcodeExpireTime) {
|
||||
clearInterval(checkLoginTimer);
|
||||
$('#status').text('二维码已过期,请点击刷新');
|
||||
$('#qrcode').css('opacity', '0.5');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/index/wechat/checkLoginStatus',
|
||||
type: 'POST',
|
||||
data: {
|
||||
scene_str: currentSceneStr,
|
||||
ticket: currentTicket
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
// 登录成功
|
||||
clearInterval(checkLoginTimer);
|
||||
$('#status').text('登录成功,正在跳转...');
|
||||
// 保存用户信息到localStorage
|
||||
if (res.data && res.data.user_info) {
|
||||
localStorage.setItem('user_info', JSON.stringify(res.data.user_info));
|
||||
}
|
||||
// 跳转到首页或其他页面
|
||||
setTimeout(function() {
|
||||
window.location.href = '/';
|
||||
}, 1000);
|
||||
} else if (res.code === 0) {
|
||||
// 更新状态信息
|
||||
$('#status').text(res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('检查登录状态失败,请重试');
|
||||
}
|
||||
});
|
||||
}, 2000); // 每2秒检查一次
|
||||
}
|
||||
|
||||
// 页面加载完成后获取二维码
|
||||
$(document).ready(function() {
|
||||
getQrcode();
|
||||
});
|
||||
|
||||
// 检查极验验证是否开启
|
||||
<?php if ($config['geetest_open'] == 1): ?>
|
||||
@ -327,17 +511,12 @@
|
||||
});
|
||||
|
||||
// 点击获取验证码按钮时验证
|
||||
document.getElementById('getCode').addEventListener('click', function () {
|
||||
var validate = captchaObj.getValidate();
|
||||
if (!validate) {
|
||||
layer.msg('请完成验证码验证', {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log('获取验证码');
|
||||
});
|
||||
var getCodeBtn = document.getElementById('getCode');
|
||||
if (getCodeBtn) {
|
||||
getCodeBtn.addEventListener('click', function () {
|
||||
console.log('获取验证码');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 直接使用配置初始化极验验证,并添加错误处理
|
||||
@ -418,9 +597,12 @@
|
||||
});
|
||||
|
||||
// 移除获取验证码按钮的验证码验证逻辑
|
||||
document.getElementById('getCode').addEventListener('click', function () {
|
||||
console.log('获取验证码');
|
||||
});
|
||||
var getCodeBtn = document.getElementById('getCode');
|
||||
if (getCodeBtn) {
|
||||
getCodeBtn.addEventListener('click', function () {
|
||||
console.log('获取验证码');
|
||||
});
|
||||
}
|
||||
<?php endif; ?>
|
||||
|
||||
// 页面加载时检查是否有保存的登录数据
|
||||
|
||||
@ -5,11 +5,16 @@
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 默认日志记录通道
|
||||
'default' => env('log.channel', 'file'),
|
||||
'default' => 'file',
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
// 日志类型记录的通道 ['error'=>'email',...]
|
||||
'type_channel' => [],
|
||||
'level' => ['error', 'warning', 'info', 'debug'],
|
||||
// 日志类型记录的通道
|
||||
'type_channel' => [
|
||||
'error' => 'file',
|
||||
'warning' => 'file',
|
||||
'info' => 'file',
|
||||
'debug' => 'file',
|
||||
],
|
||||
// 关闭全局日志写入
|
||||
'close' => false,
|
||||
// 全局日志处理 支持闭包
|
||||
@ -17,27 +22,27 @@ return [
|
||||
|
||||
// 日志通道列表
|
||||
'channels' => [
|
||||
'file' => [
|
||||
'file' => [
|
||||
// 日志记录方式
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => '',
|
||||
'path' => runtime_path() . 'log',
|
||||
// 单文件日志写入
|
||||
'single' => false,
|
||||
'single' => false,
|
||||
// 独立日志级别
|
||||
'apart_level' => [],
|
||||
'apart_level' => ['error', 'warning', 'info', 'debug'],
|
||||
// 最大日志文件数量
|
||||
'max_files' => 0,
|
||||
'max_files' => 30,
|
||||
// 使用JSON格式记录
|
||||
'json' => false,
|
||||
'json' => false,
|
||||
// 日志处理
|
||||
'processor' => null,
|
||||
'processor' => null,
|
||||
// 关闭通道日志写入
|
||||
'close' => false,
|
||||
'close' => false,
|
||||
// 日志输出格式化
|
||||
'format' => '[%s][%s] %s',
|
||||
'format' => '[%s][%s] %s',
|
||||
// 是否实时写入
|
||||
'realtime_write' => false,
|
||||
'realtime_write' => true,
|
||||
],
|
||||
// 其它日志通道配置
|
||||
],
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
use think\facade\Route;
|
||||
|
||||
// 微信接口路由
|
||||
Route::get('index/wechat/index', 'index/wechat/index');
|
||||
Route::post('index/wechat/index', 'index/wechat/index');
|
||||
Route::get('index/wechat/test', 'index/wechat/test');
|
||||
Route::get('index/wechat/getLoginTicket', 'index/wechat/getLoginTicket');
|
||||
Route::post('index/wechat/checkLoginStatus', 'index/wechat/checkLoginStatus');
|
||||
Route::post('index/wechat/reGenerateQrcode', 'index/wechat/reGenerateQrcode');
|
||||
Route::get('index/wechat/testWechat', 'index/wechat/testWechat');
|
||||
Route::post('index/wechat/testWechat', 'index/wechat/testWechat');
|
||||
|
||||
// ... existing code ...
|
||||
Loading…
x
Reference in New Issue
Block a user