Laravel导出Excel嵌入数据库LongBlob图片失败问题排查
问题排查与解决:Laravel Excel导出时LongBlob图片显示为文本
问题描述
在Laravel项目中,将存储于数据库LongBlob字段的图片嵌入导出的Excel表格时,图片以base64文本形式显示,无法正常渲染为图片。
保存图片的代码
$photo = $req->file('pic_of_transfer'); $photoData = base64_encode(file_get_contents($photo->getRealPath())); $invoice->pic_of_transfer = $photoData;
原导出Excel代码
namespace App\Exports; use App\Models\invoice; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithHeadings; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Shared\Drawing as SharedDrawing; class excelInvoiceRecords implements FromCollection, WithHeadings { protected $records; public function __construct($records) { $this->records = $records; } public function collection() { return collect($this->records)->map(function ($record) { return [ $this->getBase64Image($record->pic_of_transfer), $record->invoice_issuer, $record->issuance_date, $record->total, $record->network_paid_amount + $record->cash_paid_amount + $record->transfer_paid_amount, $record->payment_method, $record->discount, $record->tax_percentage, $record->fees_with_tax, $record->fees_without_tax, $record->invoice_type, $record->id, ]; }); } public function headings(): array { return [ 'مرفقات الفاتورة', 'الموظف المُصدر الفاتورة', 'تاريخ إصدار الفاتورة', 'إجمالي الفاتورة', 'المدفوع', 'طريقة الدفع', 'الخصم الإضافي', 'نسبة الضريبة المُضافة', 'الرسوم مع ضريبة', 'الرسوم بدون ضريبة', 'نوع الفاتورة', 'رقم الفاتورة', ]; } protected function getBase64Image($imageData) { $decodedImage = base64_decode($imageData); $tempImagePath = tempnam(sys_get_temp_dir(), 'excel_image'); file_put_contents($tempImagePath, $decodedImage); $mimeType = mime_content_type($tempImagePath); $imageData = file_get_contents($tempImagePath); unlink($tempImagePath); return 'data:' . $mimeType . ';base64,' . base64_encode($imageData); } }
控制器导出代码
$file = new excelInvoiceRecords($records); return Excel::download($file, 'Invoice reports.xlsx');
问题根源
- 文本渲染限制:
FromCollection模式仅负责填充单元格文本内容,直接返回base64字符串会被Excel识别为普通文本,无法自动解析为图片。 - 冗余操作:
getBase64Image方法中解码后重新编码的操作完全多余,浪费系统资源。
解决方法
通过PhpSpreadsheet的Drawing类手动插入图片,实现AfterSheet接口在表格生成后处理图片插入逻辑:
修改后的导出类代码
namespace App\Exports; use App\Models\invoice; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\AfterSheet; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; class excelInvoiceRecords implements FromCollection, WithHeadings, AfterSheet { protected $records; public function __construct($records) { $this->records = $records; } public function collection() { // 留空图片列单元格,用于后续插入图片 return collect($this->records)->map(function ($record) { return [ '', $record->invoice_issuer, $record->issuance_date, $record->total, $record->network_paid_amount + $record->cash_paid_amount + $record->transfer_paid_amount, $record->payment_method, $record->discount, $record->tax_percentage, $record->fees_with_tax, $record->fees_without_tax, $record->invoice_type, $record->id, ]; }); } public function headings(): array { return [ 'مرفقات الفاتورة', 'الموظف المُصدر الفاتورة', 'تاريخ إصدار الفاتورة', 'إجمالي الفاتورة', 'المدفوع', 'طريقة الدفع', 'الخصم الإضافي', 'نسبة الضريبة المُضافة', 'الرسوم مع ضريبة', 'الرسوم بدون ضريبة', 'نوع الفاتورة', 'رقم الفاتورة', ]; } // 导出完成后插入图片 public function afterSheet($event) { $sheet = $event->sheet->getDelegate(); $rowIndex = 2; // 从第2行开始(第1行是表头) foreach ($this->records as $record) { if (empty($record->pic_of_transfer)) { $rowIndex++; continue; } // 解码Base64图片数据并创建临时文件 $decodedImage = base64_decode($record->pic_of_transfer); $tempPath = tempnam(sys_get_temp_dir(), 'invoice_img'); file_put_contents($tempPath, $decodedImage); // 初始化Drawing对象并插入图片 $drawing = new Drawing(); $drawing->setPath($tempPath); $drawing->setCoordinates('A' . $rowIndex); // 指定插入到A列对应行 $drawing->setHeight(80); // 设置图片高度,可按需调整 $drawing->setWorksheet($sheet); // 调整单元格尺寸适配图片 $sheet->getRowDimension($rowIndex)->setRowHeight(80); $sheet->getColumnDimension('A')->setWidth(20); // 清理临时文件 unlink($tempPath); $rowIndex++; } } }
关键修改说明
- 移除冗余编码操作:直接解码数据库中的base64数据,避免无效的二次编码。
- 实现AfterSheet接口:在Excel表格生成完成后,通过
Drawing类将图片插入到指定单元格。 - 适配单元格尺寸:设置行高和列宽,确保图片完整显示不被裁剪。
- 空单元格占位:在
collection()中留空图片列,避免文本内容干扰图片渲染。
内容的提问来源于stack exchange,提问作者Ruba Adel
相关产品推荐
相关产品推荐

