Telegram聊天bot仅发送MySQL新数据的实现方案咨询
解决Telegram机器人重复发送问题:仅当数据库有新数据时发送消息
核心问题分析
你当前用meta http-equiv="refresh"刷新页面,每次刷新都会执行发送逻辑,导致无新数据时重复发送相同内容。核心解决思路是给每条需要发送的数据做「已发送标记」,仅处理未发送过的新数据,下面提供三种可落地的方案:
方案一:持久化记录最后发送的时间戳(最简单易实现)
通过文件/数据库记录最后一次发送消息对应的最新数据时间戳,每次执行时只查询比该时间戳新的数据,避免重复发送。
修改后的PHP发送代码
<?php // 1. 读取最后发送的时间戳(用文件存储,也可以存在数据库表中) $lastSentFile = 'last_sent_timestamp.txt'; $lastSentTimestamp = file_exists($lastSentFile) ? trim(file_get_contents($lastSentFile)) : '0000-00-00 00:00:00'; // 2. 查询仅比最后发送时间新的数据(用预处理语句防SQL注入) $stmt = $db->prepare('SELECT time_stamp, group_name, message, nvalue, old_svalue, inactive_timestamp, ack_timestamp FROM alarm WHERE time_stamp > ? ORDER BY time_stamp DESC'); $stmt->execute([$lastSentTimestamp]); $orang = $stmt->fetchAll(PDO::FETCH_ASSOC); // 3. 仅当有新数据时处理发送逻辑 if (count($orang) > 0) { $arrayAll = []; $latestTimestamp = ''; foreach($orang as $orn){ $data = implode(" ", $orn); $arrayAll[] = $data; // 记录这批数据中最新的时间戳 if ($orn['time_stamp'] > $latestTimestamp) { $latestTimestamp = $orn['time_stamp']; } } // 4. 满足nvalue条件时发送消息 if($orang[0]["nvalue"] >= 30){ // 取最新一条数据的nvalue判断 $arrayAll = implode("\n", $arrayAll); $response = $telegram->sendMessage([ 'chat_id' => "$idChat", 'text' => "\n$arrayAll", 'parse_mode' => 'HTML' ]); // 5. 更新最后发送的时间戳 file_put_contents($lastSentFile, $latestTimestamp); echo "新消息已发送"; } else { echo "Tidak dikirim"; } } else { echo "无新数据,不执行发送"; } ?>
配套HTML修改
去掉页面自动刷新的meta标签,改为手动刷新或结合AJAX局部更新表格:
<body> <table> <tr> <th>Message</th> <th>Group Name</th> <th>Time Stamp</th> </tr> <?php foreach($orang as $org): ?> <tr> <td><?php echo htmlspecialchars($org["message"]);?></td> <td><?php echo htmlspecialchars($org["group_name"]);?></td> <td><?php echo htmlspecialchars($org["time_stamp"]);?></td> </tr> <?php endforeach; ?> </table> </body>
方案二:AJAX长轮询(前端实时感知新数据)
后端阻塞等待新数据,有数据时立即返回给前端,前端触发页面更新或发送逻辑,避免无意义的页面刷新。
前端HTML+JS代码
<body> <table id="alarmTable"> <tr> <th>Message</th> <th>Group Name</th> <th>Time Stamp</th> </tr> <?php foreach($orang as $org): ?> <tr> <td><?php echo htmlspecialchars($org["message"]);?></td> <td><?php echo htmlspecialchars($org["group_name"]);?></td> <td class="timestamp"><?php echo htmlspecialchars($org["time_stamp"]);?></td> </tr> <?php endforeach; ?> </table> <script> // 长轮询函数 function startLongPoll() { // 获取页面中最新的时间戳 const timestampCells = document.querySelectorAll('.timestamp'); const lastTimestamp = timestampCells.length > 0 ? timestampCells[timestampCells.length - 1].textContent : '0000-00-00 00:00:00'; fetch(`check_new_data.php?last_ts=${encodeURIComponent(lastTimestamp)}`) .then(res => res.json()) .then(data => { if (data.hasNew) { // 有新数据,刷新页面或局部更新表格 location.reload(); } // 继续轮询(间隔1秒避免频繁请求) setTimeout(startLongPoll, 1000); }) .catch(err => { console.error('轮询出错:', err); // 出错后5秒重试 setTimeout(startLongPoll, 5000); }); } // 页面加载后启动轮询 window.onload = startLongPoll; </script> </body>
后端check_new_data.php代码
<?php // 连接数据库和Telegram实例(和原代码一致) $db = ...; $telegram = ...; $idChat = ...; $lastTimestamp = $_GET['last_ts'] ?? '0000-00-00 00:00:00'; // 查询新数据 $stmt = $db->prepare('SELECT time_stamp, group_name, message, nvalue, old_svalue, inactive_timestamp, ack_timestamp FROM alarm WHERE time_stamp > ? ORDER BY time_stamp DESC'); $stmt->execute([$lastTimestamp]); $newData = $stmt->fetchAll(PDO::FETCH_ASSOC); $response = ['hasNew' => false]; if (count($newData) > 0) { $response['hasNew'] = true; $arrayAll = []; $latestTs = ''; foreach($newData as $item){ $arrayAll[] = implode(" ", $item); if ($item['time_stamp'] > $latestTs) $latestTs = $item['time_stamp']; } // 满足条件则发送消息 if($newData[0]["nvalue"] >= 30){ $text = implode("\n", $arrayAll); $telegram->sendMessage([ 'chat_id' => "$idChat", 'text' => "\n$text", 'parse_mode' => 'HTML' ]); } } echo json_encode($response); ?>
方案三:Cron定时任务(后台静默执行,最高效)
如果不需要前端实时展示,直接用服务器定时任务定期检查数据库,有新数据就发送,完全不需要前端页面刷新。
单独的发送脚本send_alarm.php
<?php // 连接数据库和Telegram $db = ...; $telegram = ...; $idChat = ...; // 读取最后发送时间戳 $lastSentFile = 'last_sent_timestamp.txt'; $lastSentTimestamp = file_exists($lastSentFile) ? trim(file_get_contents($lastSentFile)) : '0000-00-00 00:00:00'; // 查询新数据 $stmt = $db->prepare('SELECT time_stamp, group_name, message, nvalue, old_svalue, inactive_timestamp, ack_timestamp FROM alarm WHERE time_stamp > ? ORDER BY time_stamp DESC'); $stmt->execute([$lastSentTimestamp]); $newData = $stmt->fetchAll(PDO::FETCH_ASSOC); if (count($newData) > 0) { $arrayAll = []; $latestTs = ''; foreach($newData as $item){ $arrayAll[] = implode(" ", $item); if ($item['time_stamp'] > $latestTs) $latestTs = $item['time_stamp']; } if($newData[0]["nvalue"] >= 30){ $text = implode("\n", $arrayAll); $telegram->sendMessage([ 'chat_id' => "$idChat", 'text' => "\n$text", 'parse_mode' => 'HTML' ]); file_put_contents($lastSentFile, $latestTs); } } ?>
设置Cron定时任务
在服务器上执行crontab -e,添加以下内容(每分钟执行一次脚本):
* * * * * php /path/to/your/send_alarm.php
内容的提问来源于stack exchange,提问作者Moira
相关产品推荐
相关产品推荐

