Files
wenquanauth/api/monitor.php
T
youpaishidifu 347af5537a 加固-04(P0-03): api/monitor.php 监控脚本鉴权 + 修复补单逻辑
- 增加鉴权:监控调用须带 ?key=monitor_key;密钥首次调用时自动生成
  (64hex,持久化到 sq_config setname='monitor_key',setname.inc.php
  增加种子行),hash_equals 校验,不匹配返回 403。杜绝匿名触发
  补单/清库。key 可通过 SELECT setvalue FROM sq_config WHERE
  setname='monitor_key' 获取,配置到 cron/监控服务。
- 修复 if(!!$result = select_limit_row(...) && count(...) > 0)
  运算符优先级断逻辑:拆为先取值再判断。
- 修复未定义变量 $tradeno(原 update 条件引用了从未赋值的 $tradeno)。
- trade_do 补单改为仅在状态 2->3 翻转成功(影响行数>0)时执行;
  影响行=0(已被先行进程完成)则跳过,防并发/重复补单。
- 修复 sq_apps 空表时 !array() 为真 导致误报"获取应用信息发生错误"
  (改为 false === 判断)。
- 结尾输出 JSON 结果(log/error),便于监控服务核对。

验证: 无key/错key 均 403;正确key 200;构造 status=2 测试订单,
首跑补单(agent 余额 100->110,trade 2->3),二跑无重复补单。
php -l 通过。
2026-10-10 11:32:56 +08:00

95 lines
4.1 KiB
PHP
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
/**
* 未处理数据监控程序:自动补单(已支付未完成订单)+ 清理数据库中冗余数据。
*
* 安全加固 (P0-03):
* 1. 增加鉴权:监控服务须以 {站点}/api/monitor.php?key={monitor_key} 调用;
* monitor_key 首次调用时自动生成并持久化到 sq_config(setname='monitor_key'),
* 杜绝匿名触发补单/清库。
* 2. 修复原 `if(!!$result = ... && count(...) > 0)` 断逻辑(运算符优先级错误)。
* 3. 修复未定义变量 $tradeno;trade_do 仅在状态翻转成功(影响行数>0)时执行,
* 已被先行进程完成(影响行=0)则跳过,防止重复补单。
*
* 用法:配置您的监控服务/cron 定时访问:
* http(s)://您的域名/api/monitor.php?key=<monitor_key>
* key 值可通过数据库查询:SELECT setvalue FROM sq_config WHERE setname='monitor_key';
*/
//设置链接断开仍然处理
set_time_limit(0);
ignore_user_abort(1);
//调用核心文件
include __DIR__ . '/../function/function_core.php';
/* --- 鉴权 (P0-03):key 缺失或不匹配直接拒绝 --- */
$monitor_key = isset($G['config']['monitor_key']) ? (string)$G['config']['monitor_key'] : '';
if (strlen($monitor_key) < 32) {
//尚未生成(如刚安装):生成一次并持久化(function_core 已保证 sq_config 中存在该键行)
$monitor_key = bin2hex(random_bytes(32));
updateset('monitor_key', $monitor_key);
}
if (!isset($_GET['key']) || !hash_equals($monitor_key, (string)$_GET['key'])) {
http_response_code(403);
die('403 Forbidden');
}
//获取已支付但未同步的订单信息
$error = array();
$log = array();
$result = $db->select_limit_row('sq_trade', '*', '', 5, array('status' => '2'), 'AND');
if (is_array($result) && count($result) > 0) {
include __DIR__ . '/../function/trade.inc.php';
foreach ($result as $tradeinfo) {
$tradeno = $tradeinfo['tradeno'];
/*
* 幂等补单 (P0-03):先把状态 2 -> 3(WHERE 带 status=2,翻转天然幂等),
* 仅当影响行数 > 0(本进程确实完成了翻转)才执行补单逻辑。
*/
if ($db->update('sq_trade', array('tradeno' => $tradeno, 'status' => '2'), 'AND', array('status' => 3))) {
if ($db->affected_num() > 0) {
$log[] = '[监控信息] 订单 ' . $tradeno . ' 状态翻转成功,开始补单';
trade_do($tradeinfo);
} else {
$log[] = '[监控信息] 订单 ' . $tradeno . ' 已由先行进程完成,跳过';
}
} else {
$error[] = '[监控信息]订单状态更新失败:' . $tradeno . '[Error:' . $db->geterror() . ']';
}
}
}
//清理初始化后60分钟未操作的Token数据
if ($db->delete('sq_token', '`lastest` = 0 AND `addtime` < ' . (time() - 3600) . ' AND `start` = 0', '')) {
$num = $db->affected_num();
if ($num > 0) {
$log[] = '[监控信息] 清理初始化后60分钟未操作的Token数据' . $num . '条';
}
} else {
$log[] = '[监控信息] 清理过程中发生错误:' . $db->geterror();
}
//清理心跳过期数据
$result = $db->select_all_row('sq_apps', 'ID,appname,onlinesecond');
if (false === $result) {
$log[] = '[监控信息] 获取应用信息发生错误:' . $db->geterror();
} else {
foreach ($result as $appinfo) {
if ($appinfo['onlinesecond'] > 0) {
$OutTime = intval($appinfo['onlinesecond'] * 3);
if ($db->delete('sq_token', '`appid` = ' . intval($appinfo['ID']) . ' AND `lastest` < ' . $OutTime, '')) {
$num = $db->affected_num();
if ($num > 0) {
$log[] = '[监控信息] 清理 ' . $appinfo['appname'] . ' 过期Token数据' . $num . '条';
}
} else {
$log[] = '[监控信息] 清理 ' . $appinfo['appname'] . ' 过期数据发生错误:' . $db->geterror();
}
}
}
}
//输出执行结果,便于监控服务/调用方查看
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array('code' => 1, 'log' => $log, 'error' => $error), JSON_UNESCAPED_UNICODE);