
本文介绍如何使用 php 的 `fgetcsv()` 逐行读取 csv 文件,先完整校验某列(如第4列)所有值长度是否严格等于3,仅当全部通过时才执行文件上传,避免部分校验通过即误上传的问题。
在处理用户上传的 CSV 文件时,常见的需求是:先对关键字段(如商品编码、SKU 等)进行格式校验(例如长度必须为 3),只有全部行均满足条件,才允许文件被正式保存;任意一行不达标,就中止流程并提示错误。但初学者常犯的错误是将 move_uploaded_file() 放在循环之外却未做校验结果判断——导致即使中途发现非法数据,文件仍会被上传。
✅ 正确实现逻辑:两阶段控制
核心思路是引入一个布尔标志 $valid,初始设为 true;在 while 循环中逐行读取并校验目标列(注意:$data[3] 表示第 4 列,索引从 0 开始);一旦发现 strlen($invCode) !== 3,立即置 $valid = false 并 break 跳出循环;循环结束后,仅当 $valid === true 时才执行上传操作。
以下是优化后的完整示例代码(含基础健壮性补充):
<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["csv_file"]["name"]);
$uploadOk = 1;
$valid = true;
// 检查是否为 CSV 文件
if (pathinfo($_FILES["csv_file"]["name"], PATHINFO_EXTENSION) !== 'csv') {
echo "错误:仅支持 CSV 格式文件。";
$uploadOk = 0;
}
if ($uploadOk && isset($_FILES["csv_file"]["tmp_name"]) && is_uploaded_file($_FILES["csv_file"]["tmp_name"])) {
$handle = fopen($_FILES["csv_file"]["tmp_name"], "r");
if ($handle === false) {
die("无法打开临时文件。");
}
// 逐行读取并校验第4列(索引3)长度是否严格等于3
while (($data = fgetcsv($handle)) !== false) {
// 防止空行或列数不足导致 Notice
if (!isset($data[3]) || !is_string($data[3])) {
$valid = false;
break;
}
$invCode = trim($data[3]); // 建议去除首尾空白
if (strlen($invCode) !== 3) {
$valid = false;
break;
}
}
fclose($handle);
if ($valid) {
if (move_uploaded_file($_FILES["csv_file"]["tmp_name"], $target_file)) {
echo "✅ CSV 文件上传成功,所有库存编码长度校验通过(均为3位)。";
} else {
echo "❌ 文件移动失败,请检查服务器权限或路径。";
}
} else {
echo "❌ 校验失败:至少有一行的第4列(库存编码)长度不等于3,请修正后重新上传。";
}
} else {
echo "❌ 文件上传异常,请检查表单或网络。";
}
?>⚠️ 关键注意事项:
- 变量名一致性:原文中误用 $itemCode 赋值却校验 $invCode,务必统一变量名,避免静默逻辑错误。
- 空值与边界防护:使用 isset($data[3]) 和 trim() 避免因空单元格、多余逗号或空白字符导致 strlen("") === 0 被误判。
- 资源及时释放:fopen() 后必须配对 fclose(),防止句柄泄漏。
- 安全建议:生产环境应校验 MIME 类型、限制文件大小、重命名上传文件(防 XSS/恶意脚本)、存储至非 Web 可访问目录。
通过这种「先验证、后动作」的明确分阶段设计,可确保业务规则被严格遵守,大幅提升数据导入的可靠性与用户体验。
立即学习“PHP免费学习笔记(深入)”;










