You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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');

问题根源

  1. 文本渲染限制:FromCollection模式仅负责填充单元格文本内容,直接返回base64字符串会被Excel识别为普通文本,无法自动解析为图片。
  2. 冗余操作: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++;
        }
    }
}

关键修改说明

  1. 移除冗余编码操作:直接解码数据库中的base64数据,避免无效的二次编码。
  2. 实现AfterSheet接口:在Excel表格生成完成后,通过Drawing类将图片插入到指定单元格。
  3. 适配单元格尺寸:设置行高和列宽,确保图片完整显示不被裁剪。
  4. 空单元格占位:在collection()中留空图片列,避免文本内容干扰图片渲染。

内容的提问来源于stack exchange,提问作者Ruba Adel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:30:58