PHP 8.2 用 mysqli 分批次导入 CSV 数据必须流式读取、动态控批、严格转义、手动校验:用 fopen()+fgetcsv() 防 OOM,str_getcsv() 解析防字段错乱,每行校验字段数,拼 SQL 前估算长度并限 400 行+3MB 兜底,每批执行后检查 mysqli_query() 返回值并事务回滚,禁用 LOAD DATA INFILE。

PHP 8.2 用 mysqli 导入数据,**不是“能不能导入”,而是“怎么不崩、不丢、不被注入”**——硬拼 SQL、读全文件、不校验字段数、跳过错误检查,四步就能让脚本在 5000 行时静默失败。
用 fgetcsv() 流式读 CSV,别碰 file() 或 file_get_contents()
大 CSV 文件(哪怕就 10MB)用 file() 会直接把整文件塞进内存,PHP 8.2 的 GC 再强也救不了 OOM。必须用流式:先 fopen($path, 'r'),再循环调 fgetcsv()。
- 首行是表头?用一次
fgetcsv()读掉它,别靠if ($lineNo === 1) continue—— 行号错一位,后面全偏移 - 字段含逗号或双引号?
explode(',', $line)必裂开;str_getcsv()是唯一靠谱解法,PHP 8.2 对 BOM 和嵌套引号处理更稳 - 每行解析后,立刻检查
count($fields)是否等于预期字段数,少于就error_log()记录并跳过,别硬塞
拼 INSERT INTO ... VALUES (),(),... 前必须估算长度,别信“500 行”
mysqli 默认 max_allowed_packet 是 4MB,但 500 行纯文本 + 转义字符很容易超限。拼之前不测长度,执行时只报 MySQL server has gone away,根本看不出是 SQL 太长。
- 每个字段值必须用
mysqli_real_escape_string($conn, $value)转义(注意:第一个参数是连接资源!) - 拼
VALUES时用array_map()+implode(),别手写引号 —— 漏一个单引号,整条语句就废 - 累积到约 400 行就执行,留缓冲空间;执行前加兜底:
if (strlen($sql) > 3_000_000) { mysqli_rollback($conn); break; }
事务里每批都要手动检查 mysqli_query() 返回值
PHP 8.2 的 mysqli 默认不抛异常,UNIQUE KEY 冲突、NOT NULL 插空值、类型不匹配……这些都只会让 mysqli_query() 返回 false,不会触发 catch。
立即学习“PHP免费学习笔记(深入)”;
- 必须写:
if ($result === false) { mysqli_rollback($conn); error_log("batch fail at line {$lineNo}: " . mysqli_error($conn)); break; } - 别依赖
try/catch包整个事务块 —— 除非你提前设了mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) - 事务失败后,连接可能已断,下一批前建议
mysqli_ping($conn)检查,必要时重连
别用 LOAD DATA INFILE,除非你控制得了 MySQL 配置
线上环境基本不可用:ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option 是常态。改配置、重启 MySQL、确认文件路径在白名单内——为一次导入动生产库,代价远高于 PHP 层多写几行。
-
LOAD DATA INFILE要求文件在数据库服务器本地,不是 PHP 进程所在机器 - PHP 进程用户需有
FILE权限,共享主机或云 RDS 几乎都不开 - 字段分隔符、空值识别、编码容错不如 PHP 层灵活,出错难定位,调试成本高
真正容易被忽略的点:字段长度超限(比如 VARCHAR(50) 插了 51 字符)不会报错,而是静默截断——必须在插入前用 mb_strlen() 校验,或在 MySQL 开启严格模式。



















