加固-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 通过。
This commit is contained in:
+75
-35
@@ -1,7 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 本页面为未执行数据监控程序,通过监控本脚本实现自动补单、清理数据库中的沉余数据,使程序运行效率更高
|
* 未处理数据监控程序:自动补单(已支付未完成订单)+ 清理数据库中冗余数据。
|
||||||
* 注:本脚本会由温泉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';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//设置链接断开仍然处理
|
//设置链接断开仍然处理
|
||||||
@@ -10,45 +21,74 @@ ignore_user_abort(1);
|
|||||||
|
|
||||||
//调用核心文件
|
//调用核心文件
|
||||||
include __DIR__ . '/../function/function_core.php';
|
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();
|
$error = array();
|
||||||
$log = array();
|
$log = array();
|
||||||
if(!!$result = $db->select_limit_row('sq_trade','*','',5,array('status'=>'2'),'AND') && count($result) > 0){
|
$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';
|
include __DIR__ . '/../function/trade.inc.php';
|
||||||
foreach ($result as $tradeinfo){
|
foreach ($result as $tradeinfo) {
|
||||||
if (!$db->update('sq_trade', array('tradeno' => $tradeno,'status'=>'2'), 'AND', array('status' => 3)))
|
$tradeno = $tradeinfo['tradeno'];
|
||||||
$error[] = '[监控信息]订单状态更新失败:'.$tradeinfo['tradeno'].'[Error:'.$db->geterror().']';
|
/*
|
||||||
else
|
* 幂等补单 (P0-03):先把状态 2 -> 3(WHERE 带 status=2,翻转天然幂等),
|
||||||
$log[] = '[监控信息] 订单号处理成功';
|
* 仅当影响行数 > 0(本进程确实完成了翻转)才执行补单逻辑。
|
||||||
trade_do($tradeinfo);
|
*/
|
||||||
}
|
if ($db->update('sq_trade', array('tradeno' => $tradeno, 'status' => '2'), 'AND', array('status' => 3))) {
|
||||||
}
|
if ($db->affected_num() > 0) {
|
||||||
|
$log[] = '[监控信息] 订单 ' . $tradeno . ' 状态翻转成功,开始补单';
|
||||||
//清理初始化后60分钟未操作的Token数据
|
trade_do($tradeinfo);
|
||||||
if($db->delete('sq_token','`lastest` = 0 AND `addtime` < '.(time()-3600).' AND `start` = 0','')){
|
} else {
|
||||||
$num = $db->affected_num();
|
$log[] = '[监控信息] 订单 ' . $tradeno . ' 已由先行进程完成,跳过';
|
||||||
if ($num > 0){
|
|
||||||
$log[] = '[监控信息] 清理初始化后60分钟未操作的Token数据'.$num.'条';
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$log[] = '[监控信息] 清理过程中发生错误:'.$db->geterror();
|
|
||||||
}
|
|
||||||
|
|
||||||
//清理心跳过期数据
|
|
||||||
if(!$result = $db->select_all_row('sq_apps','ID,appname,onlinesecond')){
|
|
||||||
$log[] = '[监控信息] 获取应用信息发生错误:'.$db->geterror();
|
|
||||||
}
|
|
||||||
foreach ($result as $appinfo){
|
|
||||||
if ($appinfo['onlinesecond'] >0 ){
|
|
||||||
$OutTime = $appinfo['onlinesecond'] * 3;
|
|
||||||
if($db->delete('sq_token','`appid` = '.$appinfo['ID'].' AND `lastest` < '.$OutTime,'')){
|
|
||||||
$num = $db->affected_num();
|
|
||||||
if ($num > 0) {
|
|
||||||
$log[] = '[监控信息] 清理 '.$appinfo['appname'].' 过期Token数据' . $num . '条';
|
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
$log[] = '[监控信息] 清理 '.$appinfo['appname'].' 过期数据发生错误' . $db->geterror();
|
$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);
|
||||||
|
|||||||
@@ -33,5 +33,7 @@ $SetName = array(
|
|||||||
'maindrawer'=>'',
|
'maindrawer'=>'',
|
||||||
'token'=>'',
|
'token'=>'',
|
||||||
'sid'=>'0',
|
'sid'=>'0',
|
||||||
'stime'=>'0'
|
'stime'=>'0',
|
||||||
|
// P0-03: api/monitor.php 监控鉴权密钥(首次访问监控脚本时自动生成,勿手工置空)
|
||||||
|
'monitor_key'=>''
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user