PHP fgetcsv导入CSV至MySQL时第40列左右出现异常断行问题
PHP导入CSV第40列左右断行问题排查
问题现象
使用逗号作为分隔符的CSV文件执行导入时,读取到的数据总在第40列左右出现断行;使用填充1-58顺序数字的虚拟测试CSV导入时流程正常,实际业务CSV导入触发异常。
现有导入代码
<?php // include mysql database configuration file require_once "layouts/config.php"; if (isset($_POST['submit'])) { // Open uploaded CSV file with read-only mode $csvFile = fopen(__DIR__. '/uploads/upload.csv', 'r'); //fgetcsv($csvFile); $values = array(); while (($getData = fgetcsv($csvFile, 300, ",")) !== FALSE) { $values[]= "('".$getData[0]."' , '".$getData[1]."' ,'".$getData[2]."' ,'".$getData[3]."' ,'".$getData[4]."' , '".$getData[5]."' , '".$getData[6]."' ,'".$getData[7]."' ,'".$getData[8]."' ,'".$getData[9]."' , '".$getData[10]."', '".$getData[11]."','".$getData[12]."','".$getData[13]."','".$getData[14]."', '".$getData[15]."', '".$getData[16]."','".$getData[17]."','".$getData[18]."','".$getData[19]."', '".$getData[20]."', '".$getData[21]."','".$getData[22]."','".$getData[23]."','".$getData[24]."', '".$getData[25]."', '".$getData[26]."','".$getData[27]."','".$getData[28]."','".$getData[29]."', '".$getData[30]."', '".$getData[31]."','".$getData[32]."','".$getData[33]."','".$getData[34]."', '".$getData[35]."', '".$getData[36]."','".$getData[37]."','".$getData[38]."','".$getData[39]."', '".$getData[40]."', '".$getData[41]."','".$getData[42]."','".$getData[43]."','".$getData[44]."', '".$getData[45]."', '".$getData[46]."','".$getData[47]."','".$getData[48]."','".$getData[49]."', '".$getData[50]."', '".$getData[51]."','".$getData[52]."','".$getData[53]."','".$getData[54]."', '".$getData[55]."', '".$getData[56]."','".$getData[57]."')"; } $sql = "INSERT INTO machine (PresetNumber, Dates, Starts, Stops, ProductCode, ProductName, Proper, TargetWeight1, Totals, Mean, StandardD, Maxs, Mins, ProductRange, Under, Over, OverScale, ReCheckCnt, TotalNegErr, Preset, TargetWeight2, BagLength, BagWidth, StartIPS, StopIPS, TotalTime, PlannedTime, ITPSDownTime, ITPSOff, LowProductTime, DownStreamDownTime, OperatingTime,FullProductTime,GoodBagMakingTime, NetOperatingTime, FacultyBagMakingTime, PlannedShutdown, Speed, ITPSOEE, SystemAvalability, WeigherEfficiency, BagMakerEfficiency, WeightLossRatio, ProductWaste, InputProduct, OutputProduct, AverageWeight, StandardDeviation, CombinationCount, FilledBags, GoodBags, GoodProductBags, FilmWaste, InputFilm, OutputFilm, FilmWasteUpstream, FilmWasteMiddle, FilmWasteDownStream) VALUES " . implode(',',$values); //fclose($csvFile); if ($link->query($sql) === TRUE) { echo "File(s) uploaded successfully!"; } else { echo "Error: " . $sql . "<br>" . $link->error; } }
测试用CSV数据
5,2022/05/17,16:22,11:21,AJ,,112965,39.0 g,4485.5 kg,39.707 g,0.495 g,42.0 g,39.0 g,3.0 g,1035,2218,451,58,0 g,5,39.0g,1.92inch,1.27inch,2022.5.19. 09:52,2022.5.19. 11:01,68min34sec,68min34sec,7min25sec,4min30sec,2min55sec,0min0sec,61min10sec,0min0sec,0min0sec,0min0sec,61min9sec,0,0bpm,0.0%,89.1%,0%,0.0%,0.0%,0.2%,226.3kg,225.8kg,0.000g,0.000g,5811,0,0,0,0.0%,0.00feet,0.00feet,0.0,0.0,0.0
根因定位
核心问题出在fgetcsv()函数的参数设置:
- 代码中
fgetcsv($csvFile, 300, ",")的第二个参数是单行读取长度限制,设置为300字节。 - 虚拟测试数据全为短数字,单行总长度不足300字节,因此可以正常读取所有列。
- 实际业务CSV包含大量带单位的字符串、时间格式字段,单行总长度超过300字节,
fgetcsv读取到300字节阈值时会强制截断当前行,剩余内容会被识别为下一行,刚好表现为第40列左右断行。
代码还存在几个额外隐患:
- 文件读取完成后注释了
fclose($csvFile)逻辑,会造成文件句柄泄漏。 - 直接拼接字符串生成SQL,字段中如果包含单引号、转义字符会直接触发SQL语法错误,同时存在SQL注入风险。
修复方案
- 调整
fgetcsv的长度参数,将300改为0(PHP 5.1+版本支持传0表示不限制单行长度),修改后读取逻辑为:
while (($getData = fgetcsv($csvFile, 0, ",")) !== FALSE)
- 取消
fclose($csvFile)的注释,在SQL执行完成后关闭文件句柄释放资源。 - 建议替换字符串拼接SQL的写法,改用MySQLi/PDO预处理语句实现批量插入,规避特殊字符导致的SQL错误和注入风险。
内容的提问来源于stack exchange,提问作者Mikki_M
相关产品推荐
相关产品推荐

