|
@@ -7,10 +7,8 @@ use App\Models\Api\Personnel\EmployeeOpenid as EmployeeOpenidModel;
|
|
|
use App\Facades\Servers\Logs\Log;
|
|
use App\Facades\Servers\Logs\Log;
|
|
|
use App\Servers\Wechat\Official;
|
|
use App\Servers\Wechat\Official;
|
|
|
|
|
|
|
|
-
|
|
|
|
|
class OfficialNotify extends Controller
|
|
class OfficialNotify extends Controller
|
|
|
{
|
|
{
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 公众号关注回调 - 自动绑定用户公众号OpenID
|
|
* 公众号关注回调 - 自动绑定用户公众号OpenID
|
|
|
* @author 唐远望
|
|
* @author 唐远望
|
|
@@ -18,60 +16,103 @@ class OfficialNotify extends Controller
|
|
|
* @date 2026-03-10
|
|
* @date 2026-03-10
|
|
|
*/
|
|
*/
|
|
|
public function callback(EmployeeOpenidModel $EmployeeOpenidModel)
|
|
public function callback(EmployeeOpenidModel $EmployeeOpenidModel)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 1. 处理微信服务器验证(GET请求)
|
|
|
|
|
+ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
|
|
|
+ return $this->checkSignature();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 处理微信事件推送(POST请求)
|
|
|
|
|
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
|
|
|
+ return $this->handleEvent($EmployeeOpenidModel);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 'success';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理微信事件
|
|
|
|
|
+ */
|
|
|
|
|
+ private function handleEvent($EmployeeOpenidModel)
|
|
|
{
|
|
{
|
|
|
// 获取微信推送的原始数据
|
|
// 获取微信推送的原始数据
|
|
|
$xmlData = file_get_contents('php://input');
|
|
$xmlData = file_get_contents('php://input');
|
|
|
$xml = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
$xml = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
|
- $Official = new Official();
|
|
|
|
|
- if ($xml) {
|
|
|
|
|
- // 提取关键信息
|
|
|
|
|
- $fromUsername = (string)$xml->FromUserName; // 用户的公众号OpenID
|
|
|
|
|
- $toUsername = (string)$xml->ToUserName; // 公众号原始ID
|
|
|
|
|
- $event = (string)$xml->Event; // 事件类型
|
|
|
|
|
- $eventKey = (string)$xml->EventKey; // 事件KEY值(扫码关注时会有)
|
|
|
|
|
- // 记录日志,方便调试
|
|
|
|
|
- Log::info('wechat_subscribe_info', '微信关注事件', ['FromUserName' => $fromUsername, 'ToUserName' => $toUsername, 'event' => $event, 'eventKey' => $eventKey]);
|
|
|
|
|
- // 处理关注事件
|
|
|
|
|
- if ($event == 'subscribe') {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (!$xml) {
|
|
|
|
|
+ return 'success';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 提取关键信息
|
|
|
|
|
+ $fromUsername = (string)$xml->FromUserName; // 用户的公众号OpenID
|
|
|
|
|
+ $toUsername = (string)$xml->ToUserName; // 公众号原始ID
|
|
|
|
|
+ $event = (string)$xml->Event; // 事件类型
|
|
|
|
|
+ $eventKey = (string)$xml->EventKey; // 事件KEY值(扫码关注时会有)
|
|
|
|
|
+
|
|
|
|
|
+ // 记录日志,方便调试
|
|
|
|
|
+ Log::info('wechat_subscribe_info', '微信关注事件', [
|
|
|
|
|
+ 'FromUserName' => $fromUsername,
|
|
|
|
|
+ 'ToUserName' => $toUsername,
|
|
|
|
|
+ 'event' => $event,
|
|
|
|
|
+ 'eventKey' => $eventKey
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理关注事件
|
|
|
|
|
+ if ($event == 'subscribe') {
|
|
|
|
|
+ try {
|
|
|
// 尝试获取用户UnionID
|
|
// 尝试获取用户UnionID
|
|
|
|
|
+ $Official = new Official();
|
|
|
$official_user_info = $Official->getApp()->user->get($fromUsername);
|
|
$official_user_info = $Official->getApp()->user->get($fromUsername);
|
|
|
$unionid = isset($official_user_info['unionid']) ? $official_user_info['unionid'] : '';
|
|
$unionid = isset($official_user_info['unionid']) ? $official_user_info['unionid'] : '';
|
|
|
|
|
+
|
|
|
if ($unionid) {
|
|
if ($unionid) {
|
|
|
// 1. 有UnionID,直接绑定公众号OpenID
|
|
// 1. 有UnionID,直接绑定公众号OpenID
|
|
|
$user_open_data = $EmployeeOpenidModel->where(['unionid' => $unionid])->first();
|
|
$user_open_data = $EmployeeOpenidModel->where(['unionid' => $unionid])->first();
|
|
|
if ($user_open_data) {
|
|
if ($user_open_data) {
|
|
|
$user_open_data->official_openid = $fromUsername;
|
|
$user_open_data->official_openid = $fromUsername;
|
|
|
$user_open_data->save();
|
|
$user_open_data->save();
|
|
|
|
|
+ Log::info('wechat_subscribe_success', '绑定成功', ['unionid' => $unionid, 'openid' => $fromUsername]);
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- Log::info('wechat_subscribe_error', '获取UnionID失败', ['data' => $fromUsername, 'request_data' => $official_user_info]);
|
|
|
|
|
|
|
+ Log::info('wechat_subscribe_error', '获取UnionID失败', [
|
|
|
|
|
+ 'data' => $fromUsername,
|
|
|
|
|
+ 'request_data' => $official_user_info
|
|
|
|
|
+ ]);
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (\Exception $e) {
|
|
|
|
|
+ Log::error('wechat_subscribe_exception', '处理异常', [
|
|
|
|
|
+ 'error' => $e->getMessage()
|
|
|
|
|
+ ]);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- // 验证签名
|
|
|
|
|
- $signature = $this->checkSignature();
|
|
|
|
|
- if ($signature){
|
|
|
|
|
- return $signature;
|
|
|
|
|
- }else{
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 重要:必须返回success
|
|
|
|
|
+ return 'success';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证服务器地址有效性
|
|
|
|
|
+ */
|
|
|
private function checkSignature()
|
|
private function checkSignature()
|
|
|
{
|
|
{
|
|
|
- $signature = $_GET["signature"];
|
|
|
|
|
- $timestamp = $_GET["timestamp"];
|
|
|
|
|
- $nonce = $_GET["nonce"];
|
|
|
|
|
- if (!$signature || !$timestamp || !$nonce) return false;
|
|
|
|
|
- $token = config('wechat.openplat.token', '');
|
|
|
|
|
- $tmpArr = array($token, $timestamp, $nonce);
|
|
|
|
|
|
|
+ $signature = $_GET["signature"] ?? '';
|
|
|
|
|
+ $timestamp = $_GET["timestamp"] ?? '';
|
|
|
|
|
+ $nonce = $_GET["nonce"] ?? '';
|
|
|
|
|
+ $echostr = $_GET["echostr"] ?? '';
|
|
|
|
|
+
|
|
|
|
|
+ if (!$signature || !$timestamp || !$nonce) {
|
|
|
|
|
+ return 'Invalid request';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $token = config('wechat.openplat.token', 'your_token_here');
|
|
|
|
|
+ $tmpArr = [$token, $timestamp, $nonce];
|
|
|
sort($tmpArr, SORT_STRING);
|
|
sort($tmpArr, SORT_STRING);
|
|
|
- $tmpStr = implode($tmpArr);
|
|
|
|
|
- $tmpStr = sha1($tmpStr);
|
|
|
|
|
|
|
+ $tmpStr = sha1(implode($tmpArr));
|
|
|
|
|
+
|
|
|
if ($tmpStr == $signature) {
|
|
if ($tmpStr == $signature) {
|
|
|
- return $tmpStr;
|
|
|
|
|
|
|
+ return $echostr; // 验证成功,返回echostr
|
|
|
} else {
|
|
} else {
|
|
|
- return false;
|
|
|
|
|
|
|
+ return 'Invalid signature';
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+}
|