推荐用 PhpSpreadsheet 库读取 Excel 通信录,设 UTF-8 编码、清洗字段、用 INSERT IGNORE 批量插入,并建 utf8mb4 表结构;导入后捕获 SQL 异常并分批提交事务。

PHP读取Excel班级通信录文件并插入MySQL
直接用 fgetcsv() 读取 CSV 格式通信录最稳妥;若必须处理 Excel(.xlsx/.xls),别硬写解析逻辑,用 phpspreadsheet 库——它能自动识别格式、跳过空行、处理中文乱码,比自己写 SimpleXML 或 COM 扩展靠谱得多。
常见错误是把 Excel 当纯文本用 file_get_contents() 读,结果得到一堆乱码二进制,或者用 iconv() 强转编码反而崩掉。正确做法是让库负责解包,PHP 只管字段映射。
- 确保 Excel 第一行是表头(如
name、student_id、phone、parent_phone),且无合并单元格 - 导入前用
mb_detect_encoding()检查原始内容编码,但更推荐在phpspreadsheet中统一设setInputEncoding('UTF-8') - 对手机号、学号等字段做
trim()+filter_var($val, FILTER_SANITIZE_NUMBER_INT)清洗,避免前后空格或换行符入库
批量插入时防重复、跳过非法数据
班级通信录常有重名、缺手机号、学号格式错(如“2023-001”混入字母)等问题,不能全靠前端校验。PHP 导入脚本里得做轻量级后端过滤,否则一条脏数据会导致整批 INSERT 失败或主键冲突。
推荐用 INSERT IGNORE INTO 或 INSERT ... ON DUPLICATE KEY UPDATE,前提是 MySQL 表中已为 student_id 或 name+class 组合加了唯一索引。否则光靠 PHP 判断“是否已存在”,并发导入时仍有概率漏判。
立即学习“PHP免费学习笔记(深入)”;
- 逐行验证:用
preg_match('/^[\x{4e00}-\x{9fa5}a-zA-Z\s]+$/u', $name)过滤姓名中的非法符号 - 手机号用
preg_match('/^1[3-9]\d{9}$/', $phone)粗筛(不替代运营商实名核验) - 遇到空值或验证失败的行,记录到日志数组,最后统一输出警告,但不停止导入
MySQL表结构要匹配通信录字段语义
别直接建个 contact_list 表然后塞 20 个 VARCHAR(255) 字段。班级通信录核心字段就几个:学生姓名、学号、班级、联系电话、家长电话、家庭住址。地址可设 TEXT,其他用 VARCHAR(32) 足够,学号建议加 UNIQUE 约束。
容易被忽略的是字符集和排序规则:utf8mb4_unicode_ci 必须设,否则微信昵称里的 emoji 或生僻字(如“䶮”)存不进去,报错 Incorrect string value: '\xF0\x9F\x92\xA1'...。
- 建表 SQL 示例:
CREATE TABLE class_contacts ( id INT AUTO_INCREMENT PRIMARY KEY, student_id VARCHAR(32) NOT NULL UNIQUE, name VARCHAR(32) NOT NULL, class VARCHAR(16) NOT NULL, phone VARCHAR(16), parent_phone VARCHAR(16), address TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
- 如果通信录含照片路径,不要存二进制大图,只存相对路径(如
uploads/photo_2023001.jpg),并确保该目录 Web 可读
执行导入后检查实际写入行数与报错明细
很多人以为 mysqli_affected_rows() 返回非负数就成功了,其实它只返回“被影响的行数”,不等于“成功插入的行数”。比如用 INSERT IGNORE 插入已存在的学号,返回 0,但不算失败;而某行因字段超长被截断,MySQL 默认不报错(STRICT_TRANS_TABLES 关闭时),affected_rows 仍显示 1。
真正可靠的反馈是捕获 mysqli_sql_exception 并记录具体哪一行、哪个字段出问题。简单场景下,可在循环内用 $mysqli->errno 和 $mysqli->error 实时判断。
- 开启 MySQL 严格模式:
SET sql_mode = 'STRICT_TRANS_TABLES';,让超长、空值等立刻报错 - 每 100 行做一次
mysqli_commit()(若启用了事务),避免单次导入卡死或内存溢出 - 导完别忘了关闭
phpspreadsheet的 reader 对象:$reader->close();,否则大文件可能撑爆内存











