Laravel 9使用Laravel Excel导入LibreOffice修改的Excel出现无限循环
Laravel Excel导入LibreOffice修改的XLSX文件触发无限循环问题解决
问题场景
基于Laravel 9开发的应用,通过Laravel Excel实现XLSX表格导入功能。测试时发现:
- 用LibreOffice Calc删除一行后保存的文件,导入会陷入无限循环,检测到超百万行数据;
- 用Microsoft Excel修改的同一份文件则完全正常。
已尝试但无效的方案
- 监听
BeforeExport事件,设置setReadDataOnly(true):
public function registerEvents(): array { return [ BeforeExport::class => function(BeforeExport $event) { $event->reader->getProperties()->setReadDataOnly(true); }, ]; }
- 在
AppServiceProvider中定义Reader宏调用setReadDataOnly(true):
public function boot() { Schema::defaultStringLength(191); Paginator::useBootstrapFive(); Reader::macro('setCreator', function (Reader $reader, string $creator) { $reader->getDelegate()->setReadDataOnly(true); }); }
问题根源
BeforeExport事件是导出操作触发的,导入流程不会执行这个事件,所以之前的设置完全没生效;- LibreOffice保存XLSX时,不会彻底清除已删除行的元数据,PhpSpreadsheet默认会读取这些残留的行索引,导致识别出大量空行,进而引发循环异常。
可行解决方案
方案1:改用BeforeImport事件设置读取规则
把事件换成导入触发的BeforeImport,同时设置只读数据+行过滤:
use Maatwebsite\Excel\Events\BeforeImport; use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; public function registerEvents(): array { return [ BeforeImport::class => function(BeforeImport $event) { // 设置只读数据,忽略格式等元数据 $event->reader->getDelegate()->setReadDataOnly(true); // 自定义行过滤,限制最大读取行数(可根据业务调整) $event->reader->getDelegate()->setReadFilter(new class implements IReadFilter { public function readCell($column, $row, $worksheetName = '') { // 只读取前1000行,避免读取残留空行 return $row <= 1000; } }); }, ]; }
方案2:导入时显式设置Reader参数
在导入逻辑中直接给Reader设置只读属性,确保生效:
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Excel as ExcelType; // 导入时的调用代码 $reader = Excel::reader(ExcelType::XLSX); $reader->getDelegate()->setReadDataOnly(true); $reader->import(new YourImportClass, $filePath);
方案3:遍历行时主动终止空行循环
在Import类的collection方法中,判断行是否为空,为空则跳出循环:
public function collection(Collection $rows) { foreach ($rows as $row) { $rowArray = $row->toArray(); // 判断当前行是否全为空 if (empty(array_filter($rowArray))) { break; } // 处理你的业务逻辑 // ... } }
内容的提问来源于stack exchange,提问作者fombo
相关产品推荐
相关产品推荐

