PHP执行ping检测主机存活时目标不可达误判为在线的修复方案
PHP关键设备Ping监控误判修复方案
问题原因
原有检测逻辑仅通过匹配ping返回结果中的Received = 1字段判定设备在线,但Windows环境下ping收到网关返回的Destination host unreachable(目标主机不可达)报文时,统计段同样会出现该字段——此时收到的是路由/网关返回的ICMP错误包,并非目标设备的正常存活响应,因此导致离线设备被误判为在线。
修复逻辑
在原有成功匹配规则基础上,新增错误特征排除:只要返回结果包含目标不可达、请求超时两类错误标识,无论统计字段是否显示Received=1,均判定为离线。同时修复原有代码中strpos判断不严谨、计数逻辑冲突、命令参数未转义三个隐藏bug,将检测和渲染流程拆分,保证计数准确。
修复后完整代码
function CriticalSystem( &$SC, &$FC ){ // 引用传递在线、离线计数变量 // 关键设备监控列表 $systems = array( array('ip' => '8.8.8.8', 'name' => 'Leased Line Connection (Virgin BT Failover)'), array('ip' => '192.168.11.254', 'name' => 'Hostname'), array('ip' => '192.168.11.205', 'name' => 'Hostname'), array('ip' => '192.168.11.200', 'name' => 'Hostname'), array('ip' => '192.168.11.201', 'name' => 'Hostname'), array('ip' => 'WIN-FHPBMBL2E24', 'name' => 'Hostname'), array('ip' => '192.168.11.1', 'name' => 'Hostname'), array('ip' => '192.168.11.2', 'name' => 'Hostname'), array('ip' => '192.168.11.3', 'name' => 'Hostname'), array('ip' => '192.168.11.4', 'name' => 'Hostname'), array('ip' => '192.168.11.7', 'name' => 'Hostname'), array('ip' => '192.168.11.13', 'name' => 'Hostname'), array('ip' => '192.168.11.71', 'name' => 'Hostname'), array('ip' => '192.168.11.69', 'name' => 'Hostname'), array('ip' => '192.168.11.100', 'name' => 'Hostname'), array('ip' => '192.168.11.5', 'name' => 'Hostname'), array('ip' => '192.168.11.6', 'name' => 'Hostname'), array('ip' => '192.168.11.11', 'name' => 'Hostname'), array('ip' => '192.168.11.12', 'name' => 'Hostname'), array('ip' => '192.168.11.9', 'name' => 'Hostname'), array('ip' => '192.168.11.14', 'name' => 'Hostname'), array('ip' => '192.168.11.8', 'name' => 'Hostname'), array('ip' => '192.168.11.10', 'name' => 'Hostname'), array('ip' => '192.168.11.210', 'name' => 'Hostname'), array('ip' => '192.168.11.211', 'name' => 'Hostname'), array('ip' => '192.168.11.243', 'name' => 'Hostname'), array('ip' => '192.168.11.249', 'name' => 'Hostname'), array('ip' => '192.168.11.250', 'name' => 'Hostname'), array('ip' => '192.168.11.251', 'name' => 'Hostname'), array('ip' => '192.168.11.252', 'name' => 'Hostname'), array('ip' => '192.168.11.248', 'name' => 'Hostname'), array('ip' => '192.168.11.247', 'name' => 'Hostname'), array('ip' => '192.168.11.253', 'name' => 'Hostname'), array('ip' => 'DESKTOP-AF7UN0J', 'name' => 'Hostname'), array('ip' => '192.168.11.244', 'name' => 'Hostname'), ); // 匹配规则定义 $successFlag = "Received = 1"; $errorFlags = [ "Destination host unreachable", "Request timed out" ]; $detectResults = []; $SC = 0; $FC = 0; // 第一阶段:完成所有设备ping检测 foreach ($systems as $device) { unset($pingResult); $status = "DOWN"; $hasError = false; // 转义参数避免命令注入风险 exec("ping -n 1 " . escapeshellarg($device['ip']), $pingResult); foreach($pingResult as $line) { // 先匹配错误标识,命中直接判定为离线 foreach($errorFlags as $errText) { if (stripos($line, $errText) !== false) { $hasError = true; break 2; } } // 无错误前提下匹配成功标识 if (strpos($line, $successFlag) !== false) { $status = "UP"; } } // 命中错误规则强制覆盖为离线 if ($hasError) { $status = "DOWN"; } $detectResults[] = [ 'ip' => $device['ip'], 'name' => $device['name'], 'status' => $status ]; } // 第二阶段:渲染表格并统计计数 echo "<table border='0' class='table'>"; foreach ($detectResults as $item) { if ($item['status'] == "UP") { $SC++; $statusHtml = "<img src='/Images/GTick.jpg'><span style='color:#FFFFFF'>". $SC ."</span>"; } else { $FC++; $statusHtml = "<img src='/Images/RTick.jpg'><span style='color:#FFFFFF'>". $FC ."</span>"; } echo "<tbody> <tr> <td>IP Address: {$item['ip']}</td> <td VALIGN = Middle Align = Center>Unit Name: {$item['name']}</td> </tr> <tr> <td>Status is: {$item['status']}</td> <td VALIGN = Middle Align = Center>{$statusHtml}</td> </tr> </tbody> "; } echo"</table>"; }
改动说明
- 错误拦截逻辑:只要ping结果包含目标不可达、请求超时任意一种错误特征,直接判定为离线,从根源解决Received=1误判问题
- 语法bug修复:将
strpos的判断从== TRUE改为!== false严格匹配,避免字符串出现在行首位置0时出现判断失效 - 安全加固:使用
escapeshellarg转义传入ping命令的IP/主机名参数,避免特殊字符引发命令注入风险 - 计数逻辑优化:拆分检测和渲染流程,所有设备检测完成后再遍历输出表格,在线/离线序号累加准确,不会出现原有代码最后强制覆盖$FC导致的计数错乱问题
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

