first commit

This commit is contained in:
2025-07-14 14:48:36 +08:00
commit 0c7237da45
637 changed files with 117431 additions and 0 deletions
+867
View File
@@ -0,0 +1,867 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
namespace app\index\controller;
use think\facade\Request;
use think\facade\Log;
use think\facade\Cache;
use GuzzleHttp\Client;
use app\index\model\Users;
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()
{
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(),
'real_ip' => Request::server('HTTP_X_REAL_IP'),
'forwarded_ip' => Request::server('HTTP_X_FORWARDED_FOR'),
'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'] ?? '',
'CONTENT_TYPE' => $_SERVER['CONTENT_TYPE'] ?? '',
'CONTENT_LENGTH' => $_SERVER['CONTENT_LENGTH'] ?? '',
'SERVER_NAME' => $_SERVER['SERVER_NAME'] ?? '',
'SERVER_ADDR' => $_SERVER['SERVER_ADDR'] ?? '',
'SERVER_PORT' => $_SERVER['SERVER_PORT'] ?? '',
'REQUEST_SCHEME' => $_SERVER['REQUEST_SCHEME'] ?? '',
],
'env' => [
'app_debug' => config('app.debug'),
'app_env' => config('app.env'),
'domain' => config('app.domain'),
]
];
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;
}
}
// 验证签名
protected function checkSignature()
{
try {
$signature = Request::get('signature');
$timestamp = Request::get('timestamp');
$nonce = Request::get('nonce');
$echostr = Request::get('echostr');
$debugInfo = [
'signature' => $signature,
'timestamp' => $timestamp,
'nonce' => $nonce,
'echostr' => $echostr,
'url' => Request::url(true),
'time' => date('Y-m-d H:i:s'),
'ip' => Request::ip(),
'headers' => getallheaders()
];
Log::info('微信验证参数:' . json_encode($debugInfo, JSON_UNESCAPED_UNICODE));
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('签名验证:' . json_encode($verifyInfo, JSON_UNESCAPED_UNICODE));
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;
}
}
// 接收消息
protected function receiveMessage()
{
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);
// 使用DOMDocument替代simplexml_load_string
$dom = new \DOMDocument();
$dom->loadXML($postStr, LIBXML_NOCDATA | LIBXML_NOBLANKS);
$postObj = simplexml_import_dom($dom);
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') {
try {
$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'),
'raw_data' => $postStr
]);
// 创建票据保存目录
$upload_dir = 'public/storage/uploads/ticket/';
if (!is_dir($upload_dir)) {
if (!mkdir($upload_dir, 0755, true)) {
Log::error('创建票据保存目录失败:' . $upload_dir);
return 'success';
}
Log::info('创建票据保存目录成功:' . $upload_dir);
}
// 保存扫码数据
$data = [
'openid' => $fromUsername,
'scene_str' => $scene_str,
'ticket' => $ticket,
'scan_time' => time(),
'event' => $event,
'raw_data' => $postStr
];
$content = json_encode($data, JSON_UNESCAPED_UNICODE);
$file = $upload_dir . $scene_str . "_" . $ticket . ".json";
if (file_put_contents($file, $content) === false) {
Log::error('保存扫码数据失败:' . $file);
return 'success';
}
Log::info('保存扫码数据成功:' . $file);
// 获取用户信息
try {
$accessToken = $this->getGZHAccessToken();
Log::info('获取access_token成功:' . $accessToken);
$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'])) {
// 先检查是否存在该openid的用户
$user = Users::where('openid', $fromUsername)->find();
if ($user) {
// 已存在用户,直接登录
$user->login_count = $user->login_count + 1; // 增加登录次数
$user->update_time = time(); // 更新登录时间
// 只在头像为空或为默认头像时更新
if (empty($user->avatar) || $user->avatar === '/static/images/avatar.png') {
if (!empty($userInfo['headimgurl'])) {
$user->avatar = $userInfo['headimgurl'];
} elseif (empty($user->avatar)) {
$user->avatar = '/static/images/avatar.png';
}
}
if (!$user->save()) {
Log::error('更新用户登录信息失败:' . json_encode($user->getError(), JSON_UNESCAPED_UNICODE));
return 'success';
}
Log::info('用户登录成功:' . json_encode($user->toArray(), JSON_UNESCAPED_UNICODE));
} else {
// 不存在用户,创建新用户
$user = new Users;
$user->openid = $fromUsername;
// 生成默认账号
$defaultAccount = 'wx_' . substr(md5($fromUsername), 0, 8);
$user->account = $defaultAccount;
$user->name = $defaultAccount; // 将默认账号同时设置为用户名
// 设置头像,确保有值
$user->avatar = !empty($userInfo['headimgurl']) ? $userInfo['headimgurl'] : '/static/images/avatar.png';
// 生成随机密码
$user->password = md5(uniqid() . rand(1000, 9999));
$user->create_time = time(); // 设置创建时间
$user->login_count = 1; // 首次登录,设置登录次数为1
if (!$user->save()) {
Log::error('创建用户失败:' . json_encode($user->getError(), JSON_UNESCAPED_UNICODE));
return 'success';
}
Log::info('创建新用户成功:' . json_encode($user->toArray(), JSON_UNESCAPED_UNICODE));
}
// 更新票据文件
$data = [
'uid' => (int)$user->uid, // 确保uid是整数
'name' => $user->name,
'avatar' => $user->avatar ?: '/static/images/avatar.png', // 确保avatar不为空
'openid' => $user->openid,
'user_account' => $user->account,
'user_password' => $user->password,
'expire_time' => time() + (7 * 24 * 3600), // 7天过期
'is_auto_login' => true,
'login_status' => 'success'
];
if (file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE)) === false) {
Log::error('更新票据文件失败:' . $file);
} else {
Log::info('更新票据文件成功:' . json_encode($data, JSON_UNESCAPED_UNICODE));
}
// 设置cookie
$expire = 7 * 24 * 3600; // 7天过期
cookie('user_account', $user->account, ['expire' => $expire]);
cookie('user_avatar', $user->avatar ?: '/static/images/avatar.png', ['expire' => $expire]);
cookie('user_name', $user->name, ['expire' => $expire]);
cookie('open_id', $user->openid, ['expire' => $expire]);
// 发送登录成功消息
$messageContent = [
'content' => "您好!\n您已成功登录系统。\n登录时间:" . date('Y-m-d H:i:s')
];
$this->sendCustomMessage($fromUsername, 'text', $messageContent);
Log::info('用户登录成功:' . json_encode([
'uid' => (int)$user->uid,
'name' => $user->name,
'openid' => $user->openid,
'account' => $user->account,
'cookies' => [
'user_account' => $user->account,
'user_avatar' => $user->avatar,
'user_name' => $user->name,
'open_id' => $user->openid
]
], JSON_UNESCAPED_UNICODE));
} else {
Log::error('获取用户信息失败:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE));
}
} catch (\Exception $e) {
Log::error('获取用户信息失败:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
}
} catch (\Exception $e) {
Log::error('处理扫码事件失败:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
}
}
}
return 'success';
} catch (\Exception $e) {
Log::error('处理微信消息错误:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
return 'success';
}
}
// 发送小程序卡片消息的方法
private function sendMiniProgramCard($openid)
{
$accessToken = $this->getGZHAccessToken();
print_r($accessToken);
if (!$accessToken) {
// 处理获取access_token失败的情况
return;
}
$postData = json_encode([
'touser' => $openid, // 接收者(用户)的openid
'msgtype' => 'miniprogrampage',
'miniprogrampage' => [
'title' => '小程序标题',
'appid' => '小程序appid',
'pagepath' => '小程序路径',
'thumb_media_id' => '你的thumb_media_id'
]
], JSON_UNESCAPED_UNICODE);
$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$accessToken}";
$result = json_decode(file_get_contents($url, false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-type: application/json\r\n",
'content' => $postData,
'timeout' => 60 // 超时时间(单位:s
]
])), true);
// 处理返回结果
if ($result['errcode'] == 0) {
// 发送成功
} else {
// 发送失败
}
}
// 获取公众号Access token
public function getGZHAccessToken()
{
// 从数据库获取配置
$appid = AdminConfig::where('config_name', 'wechat_appid')->value('config_value');
$secret = AdminConfig::where('config_name', 'wechat_appsecret')->value('config_value');
if (empty($appid) || empty($secret)) {
throw new \Exception('微信配置信息未设置');
}
// 构建请求URL
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
try {
// 使用 GuzzleHttp 发送请求,禁用SSL验证
$client = new Client([
'verify' => false
]);
$response = $client->get($url);
$data = json_decode($response->getBody(), true);
if (!isset($data['access_token'])) {
throw new \Exception("获取access_token失败: {$data['errmsg']}", $data['errcode'] ?? -1);
}
return $data['access_token'];
} catch (\Exception $e) {
Log::error('获取access_token失败:' . $e->getMessage());
throw $e;
}
}
/**
* 获取微信登录二维码
* @return \think\response\Json
*/
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' => $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
]
]
]);
// 发送请求获取ticket
$client = new Client(['verify' => false]);
$response = $client->post($url, [
'body' => $postData,
'headers' => [
'Content-Type' => 'application/json'
]
]);
$result = json_decode($response->getBody(), true);
if (isset($result['errcode']) && $result['errcode'] != 0) {
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_' . $new_scene_str, [
'scene_str' => $new_scene_str,
'create_time' => time(),
'expire_time' => time() + 300
], 300);
return json([
'code' => 0,
'msg' => '获取二维码成功',
'data' => [
'ticket' => $result['ticket'],
'expire_seconds' => $result['expire_seconds'],
'url' => $qrcodeUrl,
'scene_str' => $new_scene_str
]
]);
} catch (\Exception $e) {
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');
if (empty($scene_str) || empty($ticket)) {
return json(['code' => 0, 'msg' => '参数错误']);
}
// 检查票据文件
$file = 'public/storage/uploads/ticket/' . $scene_str . "_" . $ticket . ".json";
if (!file_exists($file)) {
return json(['code' => 0, 'msg' => '等待扫码']);
}
$loginData = json_decode(file_get_contents($file), true);
if (!$loginData) {
return json(['code' => 0, 'msg' => '等待扫码']);
}
// 检查是否已经扫码
if (!isset($loginData['openid'])) {
return json(['code' => 0, 'msg' => '等待扫码']);
}
// 检查登录状态
if (!isset($loginData['login_status']) || $loginData['login_status'] !== 'success') {
return json(['code' => 0, 'msg' => '正在处理登录,请稍候...']);
}
// 登录成功,设置session
session('user_id', $loginData['uid']);
session('user_name', $loginData['name']);
session('user_avatar', $loginData['avatar']);
session('user_account', $loginData['user_account']);
session('openid', $loginData['openid']);
// 删除临时文件
@unlink($file);
// 返回用户信息
return json([
'code' => 1,
'msg' => '登录成功',
'data' => [
'uid' => $loginData['uid'],
'name' => $loginData['name'],
'avatar' => $loginData['avatar'],
'openid' => $loginData['openid'],
'user_account' => $loginData['user_account'],
'user_password' => $loginData['user_password'],
'expire_time' => $loginData['expire_time'],
'is_auto_login' => $loginData['is_auto_login']
]
]);
} catch (\Exception $e) {
Log::error('检查登录状态失败:' . $e->getMessage());
return json(['code' => 0, 'msg' => '系统错误']);
}
}
/**
* 根据openid获取用户信息
* @param string $openid
* @return array|null
*/
private function getUserInfoByOpenid($openid)
{
try {
// 这里需要根据你的用户表结构来实现
// 示例:从用户表中查询openid对应的用户信息
$user = Users::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(),
'real_ip' => Request::server('HTTP_X_REAL_IP'),
'forwarded_ip' => Request::server('HTTP_X_FORWARDED_FOR'),
'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'] ?? '',
'CONTENT_TYPE' => $_SERVER['CONTENT_TYPE'] ?? '',
'CONTENT_LENGTH' => $_SERVER['CONTENT_LENGTH'] ?? '',
'SERVER_NAME' => $_SERVER['SERVER_NAME'] ?? '',
'SERVER_ADDR' => $_SERVER['SERVER_ADDR'] ?? '',
'SERVER_PORT' => $_SERVER['SERVER_PORT'] ?? '',
'REQUEST_SCHEME' => $_SERVER['REQUEST_SCHEME'] ?? '',
]
];
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');
$verifyInfo = [
'signature' => $signature,
'timestamp' => $timestamp,
'nonce' => $nonce,
'echostr' => $echostr,
'time' => date('Y-m-d H:i:s'),
'ip' => Request::ip(),
'headers' => getallheaders()
];
Log::info('微信测试接口验证参数:' . json_encode($verifyInfo, JSON_UNESCAPED_UNICODE));
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';
}
}
/**
* 发送客服消息
* @param string $openid 接收者openid
* @param string $type 消息类型
* @param array $content 消息内容
* @return bool
*/
private function sendCustomMessage($openid, $type = 'text', $content = [])
{
try {
$accessToken = $this->getGZHAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$accessToken}";
$data = [
'touser' => $openid,
'msgtype' => $type
];
if ($type === 'text') {
$data['text'] = ['content' => $content['content'] ?? '登录成功'];
}
$jsonData = json_encode($data, JSON_UNESCAPED_UNICODE);
$client = new Client(['verify' => false]);
$response = $client->post($url, [
'body' => $jsonData,
'headers' => [
'Content-Type' => 'application/json; charset=utf-8'
]
]);
$result = json_decode($response->getBody(), true);
if (isset($result['errcode']) && $result['errcode'] == 0) {
Log::info('发送客服消息成功:' . json_encode($result, JSON_UNESCAPED_UNICODE));
return true;
} else {
Log::error('发送客服消息失败:' . json_encode($result, JSON_UNESCAPED_UNICODE));
return false;
}
} catch (\Exception $e) {
Log::error('发送客服消息异常:' . $e->getMessage());
return false;
}
}
}