优先用 PhpSpreadsheet 读 .xlsx/.xls 文件,禁用 CSV 当 Excel 处理;.xlsx 是 ZIP+XML 结构,fgetcsv 无法解析;需校验上传、启用缓存、逐行迭代防内存溢出,并自行实现业务校验逻辑。

PHP 动态网站读取 Excel 文件,核心不是“能不能”,而是“用哪个库、读什么格式、怎么防崩”。直接上结论:优先用 phpspreadsheet(PHPExcel 已废弃),且只处理 .xlsx 和 .xls,别碰 .csv 当 Excel 用——它根本不是 Excel 格式,强行用 Excel 库读会出诡异乱码或空行。
为什么不能用 fgetcsv() 直接读 .xlsx
因为 .xlsx 是 ZIP 压缩包套 XML 结构,不是纯文本。用 fgetcsv() 打开只会看到乱码二进制头,报错类似 Warning: fgetcsv() expects parameter 1 to be resource, bool given 或直接空数组。只有 .csv 文件才能用原生函数安全读取,但要注意编码(通常是 UTF-8 BOM)和字段分隔符(逗号/分号/制表符)。
用 phpspreadsheet 读 .xlsx 的最小可行写法
安装:composer require phpoffice/phpspreadsheet。关键点不是“怎么装”,而是“怎么避免内存爆掉”:
- 用
IOFactory::load()加载文件前,先检查$_FILES['file']['tmp_name']是否存在且非空,否则load()会抛InvalidArgumentException - 读大文件(>5MB 或 >1w 行)必须启用缓存:
CellCacheFactory::setCacheImplementation('memory');改为'php_file'或'redis'(需扩展) - 不要用
$worksheet->toArray()一次性转全表——它把整张 Sheet 拉进内存,10w 行 × 20 列轻松吃光 512MB 内存 - 推荐逐行迭代:
foreach ($worksheet->getRowIterator() as $row),再用$cell = $row->getCellIterator(); $cell->setIterateOnlyExistingCells(true);跳过空单元格
上传 Excel 后常见报错及对应解法
用户上传的 Excel 往往不规范,得提前兜底:
立即学习“PHP免费学习笔记(深入)”;
-
ZipArchive::open(): Cannot open file→ 文件后缀是.xls但实际是.xlsx(或反之),用finfo_open(FILEINFO_MIME_TYPE)检测真实 MIME:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet才是真.xlsx - 中文列名读出来是乱码或空 → 不是编码问题,是 Excel 自身用了非标准字体或合并单元格干扰了坐标,改用
$cell->getValue()+$cell->getFormattedValue()对比判断 - 日期变成数字(如
44197)→ Excel 日期是自 1900-01-01 起的天数,用DateTime::createFromExcelDate($value)转(phpspreadsheet内置方法) - 上传失败但没报错 → 检查
php.ini的upload_max_filesize和post_max_size,二者都得 ≥ 你允许的最大 Excel 大小
真正难的不是读取,而是校验:用户传个空表、列顺序错位、必填字段为空、数字列混了文字——这些逻辑得自己写,phpspreadsheet 只负责“打开”和“取值”,不会替你判断“这行数据合不合理”。










