PHP文件入库脚本异常排查:非法字符/行数错误致任务阻塞
气象数据入库脚本阻塞问题排查与修复
核心问题点分析
1. 文件资源操作错误
修改后的代码里$fileToString = file_get_contents($file);完全错误——file_get_contents()接收的是文件路径字符串,不是fopen()返回的文件资源句柄。这会导致$fileToString获取失败,后续合法性判断全错,同时打乱文件指针位置,造成读取异常。
2. 异常文件未释放资源
当文件不符合合法性条件时(else if分支不执行),代码未调用fclose($file)释放文件资源。未关闭的句柄会被系统占用,轻则导致后续文件无法打开,重则造成进程阻塞。
3. 文件合法性判断逻辑漏洞
- 行数值判断不准确:正常文件有9行数据,对应8个换行符,但如果文件最后一行无换行(如异常示例2),
substr_count($fileToString, "\n") == 8会误判为合法;而有空行的异常文件(示例1)换行符数量超标,直接被跳过但未清空文件,导致下次循环重复处理该异常文件,陷入死循环阻塞后续流程。 - 非法字符检测正则错误:原正则
/^£$%&*()}{@#~?><>,|=_+¬¤ÇÓü]/中的^是行首锚定符,仅会匹配字符串开头的非法字符,根本检测不到字符串中间的非法内容(如示例1里的0.0¤)。正确写法应去掉^,改为检测整个字符串是否包含目标字符的字符集正则。 - 空行判断逻辑无效:
fgets($file) != ""读取第一行后移动了文件指针,虽然后续用rewind()移回,但如果第一行是空的就直接跳过,不符合“检查文件是否为空”的实际需求。
4. 异常文件未清理
不符合条件的文件未执行清空操作,导致脚本每次循环都会重复处理同一个异常文件,永远无法进入后续文件的处理流程,这是阻塞的直接原因。
修复后的代码示例
foreach ($listWeathStatV2 as $weathStat) { $filePath = __DIR__ . "/data/DB_" . $weathStat . ".txt"; $file = fopen($filePath, "r") or die("无法打开文件: " . $filePath); $fileContent = fread($file, filesize($filePath)); fclose($file); // 提前关闭资源,避免占用 $isValid = true; // 检查文件是否为空 if (trim($fileContent) === "") { $isValid = false; } // 检查非法字符(修正正则,转义特殊字符) elseif (preg_match('/[£\$%&*()}{@#~?><>,|=_+¬¤ÇÓü]/', $fileContent)) { $isValid = false; } // 检查行数(按换行分割后计数,兼容最后一行无换行的情况) $lines = preg_split('/\r?\n/', trim($fileContent)); if (count($lines) !== 9) { $isValid = false; } if ($isValid) { // 重新打开文件读取数据 $file = fopen($filePath, "r") or die("无法打开文件: " . $filePath); $heure = trim(fgets($file)); $temp = trim(fgets($file)); $humidity = trim(fgets($file)); $pressure = trim(fgets($file)); $pluvio = trim(fgets($file)); $anemo = trim(fgets($file)); $gir = trim(fgets($file)); $lumino = trim(fgets($file)); $battLvl = trim(fgets($file)); fclose($file); // 使用预编译语句防止SQL注入 $query = "INSERT INTO " . $weathStat . " (heure, valTemp, valHumid, valPressure, valPluvio, valAnemo, valGir, valLumino, battLevel) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = mysqli_prepare($connect, $query); mysqli_stmt_bind_param($stmt, "sdddddddd", $heure, $temp, $humidity, $pressure, $pluvio, $anemo, $gir, $lumino, $battLvl); mysqli_stmt_execute($stmt) or die("SQL执行错误: " . mysqli_error($connect)); mysqli_stmt_close($stmt); } // 无论文件是否合法,都清空文件,避免重复处理 file_put_contents($filePath, ""); }
额外优化说明
- 提前拼接文件路径,避免重复计算;
- 先读取内容并关闭资源,减少系统资源占用;
- 用
trim()处理每行数据,去除换行符和多余空格; - 改用MySQLi预编译语句,彻底规避SQL注入风险;
- 统一清空文件,确保不会重复处理同一文件,阻塞后续流程。
内容的提问来源于stack exchange,提问作者Laurent
相关产品推荐
相关产品推荐

