Laravel使用Maatwebsite/excel导入Excel图片并存库实现方法
Maatwebsite/Excel 导入带图片Excel存数据库实现方案
核心逻辑
Maatwebsite/Excel 默认的行数据读取逻辑仅解析单元格文本值,嵌入Excel的图片属于独立的Drawing绘图对象,不会自动挂载到$row->toArray()返回的数组中,因此直接读取$row['image_path']无法获取图片内容。
Excel示例

原有实现代码
<?php namespace App\Imports; use App\SubmissionDetail; use Maatwebsite\Excel\Row; use Maatwebsite\Excel\Concerns\OnEachRow; use Maatwebsite\Excel\Concerns\WithHeadingRow; class SubmissionDetailImport implements OnEachRow, WithHeadingRow { protected $id; function __construct($id) { $this->id = $id; } public function onRow(Row $row) { $row = $row->toArray(); $submissionDetails = SubmissionDetail::firstOrCreate( ['submission_id' => $this->id, 'nama_barang' => $row['nama_barang']], [ 'submission_id' => $this->id, 'nama_barang' => $row['nama_barang'], 'image_path' => $row['image_path'], 'jumlah' => $row['jumlah'], 'harga_satuan' => $row['harga_satuan'], 'harga_total' => $row['harga_total'], 'keterangan' => $row['keterangan'], ] ); if (! $submissionDetails->wasRecentlyCreated) { $submissionDetails->update([ 'image_path' => $row['image_path'], 'jumlah' => $row['jumlah'], 'harga_satuan' => $row['harga_satuan'], 'harga_total' => $row['harga_total'], 'keterangan' => $row['keterangan'], ]); } } }
落地实现步骤
- 导入类新增实现
WithDrawings接口,该接口为扩展包官方提供,专门用于解析Excel内嵌入的图片、绘图对象。 - 新增类属性存储图片与所在行号的映射关系,在
drawings()方法中遍历所有嵌入图片,记录图片二进制内容、后缀、对应行号。 - 行处理逻辑中,根据当前行号匹配对应图片,将图片保存到本地存储目录,获取可访问的存储路径后写入数据库。
修正后可直接使用的代码
<?php namespace App\Imports; use App\SubmissionDetail; use Maatwebsite\Excel\Row; use Maatwebsite\Excel\Drawing; use Maatwebsite\Excel\Concerns\OnEachRow; use Maatwebsite\Excel\Concerns\WithHeadingRow; use Maatwebsite\Excel\Concerns\WithDrawings; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; class SubmissionDetailImport implements OnEachRow, WithHeadingRow, WithDrawings { protected $id; // 存储图片与行号的映射关系 protected array $imageMap = []; public function __construct($id) { $this->id = $id; } /** * 注册图片解析处理器 */ public function drawings(): array { $imageMap = &$this->imageMap; return [ new class($imageMap) implements Drawing { private array $imageMap; public function __construct(array &$imageMap) { $this->imageMap = &$imageMap; } /** * 每解析到一张嵌入图片就会触发该方法 * @param mixed $image 图片二进制内容 * @param string $path 图片原始文件名 * @param int $row 图片锚定的行号(从1开始计数) * @param string $column 图片锚定的列名 */ public function setImage($image, $path, $row, $column) { $this->imageMap[$row] = [ 'content' => $image, 'extension' => pathinfo($path, PATHINFO_EXTENSION) ?: 'png' ]; } } ]; } public function onRow(Row $row) { $rowIndex = $row->getIndex(); $rowData = $row->toArray(); $imagePath = $rowData['image_path'] ?? null; // 匹配当前行对应的图片,保存到本地 if (isset($this->imageMap[$rowIndex])) { $image = $this->imageMap[$rowIndex]; $fileName = Str::random(20) . '.' . $image['extension']; // 保存到public磁盘的submission-images目录,执行php artisan storage:link后可通过web访问 Storage::disk('public')->put('submission-images/' . $fileName, $image['content']); $imagePath = 'submission-images/' . $fileName; } $submissionDetails = SubmissionDetail::firstOrCreate( ['submission_id' => $this->id, 'nama_barang' => $rowData['nama_barang']], [ 'submission_id' => $this->id, 'nama_barang' => $rowData['nama_barang'], 'image_path' => $imagePath, 'jumlah' => $rowData['jumlah'], 'harga_satuan' => $rowData['harga_satuan'], 'harga_total' => $rowData['harga_total'], 'keterangan' => $rowData['keterangan'], ] ); if (! $submissionDetails->wasRecentlyCreated) { $submissionDetails->update([ 'image_path' => $imagePath, 'jumlah' => $rowData['jumlah'], 'harga_satuan' => $rowData['harga_satuan'], 'harga_total' => $rowData['harga_total'], 'keterangan' => $rowData['keterangan'], ]); } } }
注意事项
- 代码基于Maatwebsite/Excel 3.1+版本编写,使用前请确认扩展包版本符合要求。
- 首次使用public磁盘存储文件前,需要执行
php artisan storage:link命令创建软链接,否则前端无法访问存储的图片。 - 如果Excel中图片存在行偏移(比如图片锚定行和实际对应数据行差1-2行),只需要在匹配图片时给
$rowIndex加减对应偏移值即可。 - 如果单行存在多张图片,可以将
$imageMap改为按行号+列名存储二维结构,分别匹配不同字段对应的图片。
内容的提问来源于stack exchange,提问作者ipeenk downloader
相关产品推荐
相关产品推荐

