如何获取日志中用户登录失败次数及日期?PHP代码故障排查
解决PHP读取登录失败日志时跨行读取的问题
你遇到的问题根源很明确:在每次循环里调用了两次$file->fgetcsv("|"),这个方法每次执行都会读取文件的下一行内容。第一次调用拿到第一行数据,第二次调用直接跳到第二行,自然就把第一行的用户名和第二行的日期拼在一起了,完全不符合预期。
咱们先看你的原始日志格式,每一行都是用|分隔的字段,结构是:用户名|日期|IP|主机|Failed(少数行日期格式不同,但不影响提取)。接下来我会帮你修正代码,同时实现你真正需要的「统计用户登录失败次数及对应日期详情」的需求:
修正后的完整代码
<?php // 初始化统计数组,键是用户名,值是包含次数和日期列表的数组 $loginFailStats = []; $file = new SplFileObject("failed.log", "r"); // 设置CSV的分隔符为| $file->setCsvControl("|"); while (!$file->eof()) { // 只调用一次fgetcsv,获取当前行的所有字段 $row = $file->fgetcsv(); // 跳过空行或者格式不正确的行 if (empty($row) || count($row) < 5) { continue; } $username = trim($row[0]); $date = trim($row[1]); // 统计逻辑 if (!isset($loginFailStats[$username])) { $loginFailStats[$username] = [ 'count' => 0, 'dates' => [] ]; } $loginFailStats[$username]['count']++; $loginFailStats[$username]['dates'][] = $date; } // 输出统计结果 echo "登录失败统计结果:\n"; foreach ($loginFailStats as $user => $stats) { echo "- 用户 *{$user}* 登录失败 {$stats['count']} 次,失败日期:\n"; foreach ($stats['dates'] as $date) { echo " - {$date}\n"; } } ?>
代码说明
- 用
$file->setCsvControl("|")提前设置CSV分隔符,调用fgetcsv()时无需重复传参,代码更规范。 - 每次循环只调用一次
fgetcsv(),确保拿到当前行的完整数据,彻底避免跨行读取的问题。 - 加入了空行和无效行的判断,防止日志里的异常行导致程序出错。
- 用关联数组
$loginFailStats存储每个用户的失败次数和日期列表,完美匹配你的统计需求。
预期输出
运行这段代码后,你会得到清晰的统计结果,类似这样:
登录失败统计结果:
- 用户 John 登录失败 1 次,失败日期:
- 26:Dec:2017:16:09:45
- 用户 cena 登录失败 1 次,失败日期:
- 26:Dec:2017:16:15:27
- 用户 Abc 登录失败 2 次,失败日期:
- 27:Dec:2017:09:25:25
- 04/Jan/2018 15:54:35
- 用户 Bhumi 登录失败 2 次,失败日期:
- 29:Dec:2017:09:39:45
- 29:Dec:2017:10:19:28
- 用户 Avccc 登录失败 1 次,失败日期:
- 29/Dec/2017 14:15:41
这样就完全解决了你之前的跨行读取问题,同时满足了统计需求。
内容的提问来源于stack exchange,提问作者Shivu
相关产品推荐
相关产品推荐

