
本文介绍如何在 php 批量处理 xml 文件时,当 sql 查询失败(如未查到 gean 值)时阻止文件被移动,确保异常文件保留在源目录,同时不影响其余文件的正常处理。核心方案是引入布尔标志控制后续保存与移动逻辑。
本文介绍如何在 php 批量处理 xml 文件时,当 sql 查询失败(如未查到 gean 值)时阻止文件被移动,确保异常文件保留在源目录,同时不影响其余文件的正常处理。核心方案是引入布尔标志控制后续保存与移动逻辑。
在批量处理 XML 文件并依赖数据库查询更新内容的场景中,一个常见痛点是:单个文件处理出错不应导致其被误移入目标目录。原始脚本的问题在于,无论 foreach 循环中是否发生错误(例如 $result['GEAN'] 为空),rename() 操作始终执行,造成“带错误的文件也被归档”的逻辑缺陷。
✅ 正确做法:使用处理状态标志(Flag)
关键改进是在每个文件处理开始时声明一个布尔变量(如 $save = true),并在检测到错误时将其设为 false;仅当该标志保持 true 时,才执行 DOMDocument::save() 和 rename():
// 在处理每个文件前初始化标志
$save = true;
foreach ($xpath->query("/Order/OrderLines") as $node) {
$SKU_CODE = $node->getElementsByTagName("Code")->item(0)->nodeValue;
$query = "SELECT GEAN FROM SKU WHERE SKU = '" . addslashes($SKU_CODE) . "'";
$exec = odbc_exec($connect, $query);
$result = odbc_fetch_array($exec);
// 错误判断:查询失败 或 GEAN 字段为空/不存在
if ($result === false || !isset($result['GEAN']) || $result['GEAN'] === null) {
$save = false; // ⚠️ 标记当前文件禁止移动
// 发送告警邮件(建议添加日志记录)
$to = "admin@example.com";
$subject = "XML Processing Error: GEAN Not Found";
$message = "SKU '$SKU_CODE' has no GEAN in database. File: $source_file";
mail($to, $subject, $message, "From: system@localhost\r\nContent-Type: text/plain");
// 可选:立即跳出当前文件循环,避免后续无效操作
break;
}
// ✅ 仅当无错误时才更新 XML 节点
$skuNode = $node->getElementsByTagName("SKU")->item(0);
if ($skuNode) {
$skuNode->nodeValue = '';
$skuNode->appendChild($xml->createTextNode($result['GEAN']));
}
}
// ? 仅当全程无错误时才保存并移动
if ($save) {
$xml->formatOutput = true;
$xml->save($source_file);
if (rename($source_file, $destination_file)) {
echo "✓ Processed and moved: $file\n";
} else {
error_log("Failed to move $source_file to $destination_file");
}
} else {
echo "⚠ Skipped due to error: $file\n";
}? 注意事项与最佳实践
- SQL 注入防护:原始代码直接拼接 $SKU_CODE,存在严重安全风险。务必使用 addslashes()(临时方案)或升级至 PDO/MySQLi 并采用预处理语句。
- 数据库连接健壮性:odbc_connect() 应检查返回值,连接失败需提前终止或记录。
- 空结果集处理:odbc_fetch_array() 对空结果返回 false,但需注意 odbc_exec() 本身失败也会返回 false —— 建议补充 odbc_error() 日志。
-
性能优化(进阶):若 XML 中 SKU 数量大且数据库条目有限,可预先一次性查询所有有效 SKU => GEAN 映射到关联数组,避免循环内多次查询:
$geanMap = []; $mapQuery = "SELECT SKU, GEAN FROM SKU WHERE GEAN IS NOT NULL"; $mapExec = odbc_exec($connect, $mapQuery); while ($row = odbc_fetch_array($mapExec)) { $geanMap[$row['SKU']] = $row['GEAN']; } // 后续用 isset($geanMap[$SKU_CODE]) 替代每次查询 - 原子性保障:生产环境建议先 copy() 再 unlink() 源文件,避免 rename() 失败导致数据丢失。
通过引入状态标志并合理组织控制流,即可精准实现“错误即止、余者照常”的健壮文件处理逻辑,大幅提升脚本可靠性与可维护性。



















