为什么PHP执行LOAD DATA INFILE导入CSV时库存字段值为0
问题描述
我寻找该问题的解决方案已有近1年时间,具体情况如下:
- 我的数据库部署在Ubuntu Apache服务器上,当前存储约200万条数据。供应商会定期上传库存文件,服务器每小时通过cron任务删除原有库存表后,从供应商提供的文件重新导入数据,保证库存水平和价格的时效性不超过1小时。
- 供应商通常提供CSV或TXT格式的数据,我通过Apache服务器上的PHP文件执行
LOAD DATA INFILE命令完成导入,支撑网站用户的数据库访问需求。 - 整体流程对绝大多数供应商都运行正常,我会为每个供应商根据其文件格式编写专属的导入命令。但有一家供应商的CSV文件看起来正常,却出现导入问题:
- 通过PHP脚本自动执行导入时,描述、价格等所有字段都能正常导入,唯独库存数量字段始终显示0,和CSV中的实际数值不符;但完全相同的命令在PHPMyAdmin中执行时,库存数量可以正常导入,因此可以确认源文件没有损坏。
- 我试过将CSV文件重命名为TXT来消除格式影响,问题依旧;也尝试过将Quantity字段类型从INT(4)依次修改为FLOAT(4,0)、TEXT、VARCHAR,均导入失败:字段为VARCHAR类型时库存数据为空,其他数据类型时均显示为0。
- 我已经检查过CSV文件中库存数量字段的格式为通用格式,无特殊格式设置,其他30余家供应商的同类文件均无异常,无法定位源数据的问题点。
相关代码
PHPMyAdmin中可正常执行的MySQL命令
LOAD DATA INFILE '/var/www/html/datafiles/FTP/company/company.txt' INTO TABLE `supplier-data` FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES (`Man_Pt_Nr`, `Sup_Pt_Nr`, `Manufacturer`, `Description`, `Qty`, `Cost`, `Condition`) SET `Disti` = 'Company Name', `shipping` = '£10.00';
PHP中执行会出现库存字段导入为0的代码
mysql_query ("LOAD DATA INFILE '/var/www/html/datafiles/FTP/company/company.txt' INTO TABLE `supplier-data` FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES (`Man_Pt_Nr`, `Sup_Pt_Nr`, `Manufacturer`, `Description`, `Qty`, `Cost`, `Condition`) SET `Disti` = 'Company Name', `shipping` = '£10.00';" );
导入数据样例
Manufacturer part number,SKU,Manufacturer name,Product name,Quantity in stock,Price list 1,Product condition code 500208-562-2304528AS,"2304528AS","Hewlett Packard Enterprise","1GB DDR3 PC3-10600 1333Mhz DIMM 240pin Ecc (AS)","19","2.00","AS" E5470-NL-SB198-R4,"2337083R4","Dell","LAT E5470 i5-6300U/8GB/128GB-SSD/14""HD/W10P CMAR WLAN/BT/Single Point/Cover protection sticker (R4)","2","183.00","R4" LAT7480-NL-SB106-R4,"2337512R4","Dell","FlexIT Dell Latitude 7480 (Refurbished) 7th gen Intel® Core? i5 2.6 GHz 35.6 cm (14"";) 1920 x 1080 pixels 8 GB 256 GB","68","378.00","R4" EURO-C13-STD-5/6FT-N2,"2215545N2","Universal","EURO 230V C13 Power Cable Black 5-6ft/1 50-1 80M (N2)","14686","2.00","N2"
解决方案
根因说明
- 核心问题是PHP代码中SQL语句的双引号未做转义,PHP解析字符串时会将SQL内部的双引号识别为字符串结束符,导致SQL语句被截断,字段映射顺序错乱,库存字段实际读取到的是其他列的内容,因此显示为0或空。
- 次要问题是未兼容供应商文件的Windows格式换行符(
\r\n),phpMyAdmin执行时会自动兼容多种换行符,而PHP中硬编码的\n会导致行解析错位,进一步加剧字段映射错误。 - 当前使用的
mysql_*系列扩展已被官方废弃,存在底层字符处理兼容性缺陷,也可能引发该问题。
修复步骤
- 修复PHP字符串转义问题,优先改用单引号包裹SQL字符串,避免内部双引号的转义冲突,示例如下:
// 改用单引号包裹SQL字符串,消除转义冲突 mysql_query('LOAD DATA INFILE \'/var/www/html/datafiles/FTP/company/company.txt\' INTO TABLE `supplier-data` FIELDS TERMINATED BY \',\' ENCLOSED BY \'"\' ESCAPED BY \'"\' LINES TERMINATED BY \'\r\n\' IGNORE 1 LINES (`Man_Pt_Nr`, `Sup_Pt_Nr`, `Manufacturer`, `Description`, `Qty`, `Cost`, `Condition`) SET `Disti` = \'Company Name\', `shipping` = \'£10.00\';');
- 将换行符设置为
\r\n兼容Windows格式的库存文件,避免行解析错位。 - 若仍有异常,可通过用户变量接收原始字段内容,清洗掉不可见字符后再赋值给库存字段,参考SQL如下:
LOAD DATA INFILE '/var/www/html/datafiles/FTP/company/company.txt' INTO TABLE `supplier-data` FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\r\n' IGNORE 1 LINES (`Man_Pt_Nr`, `Sup_Pt_Nr`, `Manufacturer`, `Description`, @raw_qty, `Cost`, `Condition`) SET `Disti` = 'Company Name', `shipping` = '£10.00', `Qty` = CAST(TRIM(@raw_qty) AS UNSIGNED);
- 长远建议替换废弃的
mysql_*扩展为mysqli或PDO,消除底层兼容性隐患。
内容的提问来源于stack exchange,提问作者Tony M
相关产品推荐
相关产品推荐

