Laravel 10下如何验证上传Excel为官网下载的原文件?
可行方案及实现思路(Laravel 10)
针对你需求的核心——确保上传文件是官网下发的原模板,以下是几个落地性强的方案,结合Laravel的加密、Excel处理能力实现:
方案一:隐藏工作表存储加密令牌(推荐)
利用Excel支持隐藏工作表的特性,在模板文件中新增一个用户不可见的工作表,存储加密后的唯一令牌,上传时读取该令牌解密校验。用户几乎不会主动修改隐藏工作表,安全性较高。
实现步骤
生成带隐藏校验表的模板文件
借助maatwebsite/laravel-excel包(Laravel常用Excel处理工具)生成模板,新增隐藏工作表存储加密令牌:use Maatwebsite\Excel\Facades\Excel; use Illuminate\Support\Str; use Illuminate\Encryption\Encrypter; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; // 生成唯一UUID令牌并加密 $token = Crypt::encryptString(Str::uuid()); // 生成带隐藏校验表的Excel模板 Excel::store(new class($token) implements FromCollection, WithSheets, WithEvents { private $token; public function __construct($token) { $this->token = $token; } // 主工作表(用户填写数据的模板) public function collection() { return collect([ ['姓名', '邮箱', '手机号'], // 自定义校验规则的表头 ['示例:张三', '示例:test@xxx.com', '示例:138xxxxxxx'] ]); } // 定义多个工作表 public function sheets(): array { return [ '数据填写模板' => $this, '_verify' => new class($this->token) implements FromCollection { private $token; public function __construct($token) { $this->token = $token; } public function collection() { return collect([[$this->token]]); // 令牌存A1单元格 } } ]; } // 隐藏校验工作表 public function registerEvents(): array { return [ AfterSheet::class => function(AfterSheet $event) { $event->sheet->getDelegate()->getParent() ->getSheetByName('_verify') ->setSheetState(Worksheet::SHEETSTATE_HIDDEN); } ]; } }, 'official_template.xlsx');上传时校验令牌
读取上传文件的隐藏工作表内容,解密后验证合法性:use Maatwebsite\Excel\Facades\Excel; $uploadedFile = $request->file('excel_file'); try { // 读取隐藏工作表的令牌 $verifyData = Excel::toArray(new class { public function collection(array $rows) { return $rows[0][0] ?? null; } }, $uploadedFile)->get('_verify'); $encryptedToken = $verifyData[0][0] ?? ''; // 解密令牌并验证格式 $decryptedToken = Crypt::decryptString($encryptedToken); if (!Str::isUuid($decryptedToken)) { throw new \Exception('令牌格式无效'); } // 可选:如果需要绑定用户,可将令牌存入数据库,上传时校验是否属于当前用户 // $isValid = DB::table('template_tokens')->where(['user_id' => auth()->id(), 'token' => $decryptedToken])->exists(); // if (!$isValid) throw new \Exception('非当前用户下载的模板'); } catch (\Exception $e) { return back()->withErrors('文件无效,请使用官网下载的模板'); } // 校验通过,处理用户填写的数据 $userData = Excel::toArray(new class { public function collection(array $rows) { return array_slice($rows, 1); // 跳过表头和示例行 } }, $uploadedFile)->get('数据填写模板');
方案二:自定义文档属性存储令牌
利用Excel的自定义文档属性功能,将加密令牌存入文件属性中,上传时读取该属性校验。
实现步骤
生成带自定义属性的模板
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // 设置主工作表内容(表头、示例等) $sheet->setCellValue('A1', '姓名')->setCellValue('B1', '邮箱')->setCellValue('C1', '手机号'); // 添加加密令牌到自定义属性 $properties = $spreadsheet->getProperties(); $properties->setCustomProperty('official_verify_token', Crypt::encryptString(Str::uuid())); $writer = new Xlsx($spreadsheet); $writer->save('official_template.xlsx');上传时校验属性
use PhpOffice\PhpSpreadsheet\IOFactory; $uploadedFile = $request->file('excel_file'); $spreadsheet = IOFactory::load($uploadedFile->getPathname()); $properties = $spreadsheet->getProperties(); $encryptedToken = $properties->getCustomProperty('official_verify_token'); if (!$encryptedToken) { return back()->withErrors('文件无效'); } try { $decryptedToken = Crypt::decryptString($encryptedToken); if (!Str::isUuid($decryptedToken)) { throw new \Exception('令牌无效'); } } catch (\Exception $e) { return back()->withErrors('文件无效,请使用官网下载的模板'); }
方案三:哈希校验结合结构验证
如果不需要绑定用户,可预先计算模板文件的哈希值(排除用户填写区域),上传时校验文件结构(工作表数量、表头、格式)+ 核心区域哈希。但注意用户填写数据后文件哈希会变化,因此仅适合校验模板的原始结构。
核心思路
- 预先存储模板的表头哈希、工作表数量等特征值
- 上传时读取文件的表头,计算哈希后与存储值比对
- 结合令牌方案使用,双重验证提升安全性
内容的提问来源于stack exchange,提问作者kamel dev
相关产品推荐
相关产品推荐

