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

Laravel中如何防止子文件夹出现重复文件?

问题描述

我创建了一个支持多文件同时上传的添加视图,文件上传路径格式为:Drawings/PartNumber/Type/filename.extension

我需要确保Drawings文件夹下所有子路径中,都不能存在同名且同扩展名的文件,以下这些情况都不被允许:

  • Drawings/PartNumber1/Type1/filename1.pdf
  • Drawings/PartNumber2/Type2/filename1.pdf
  • Drawings/PartNumber1/Type3/filename1.pdf
  • Drawings/PartNumber1/filename1.pdf
  • Drawings/filename1.pdf

我的处理函数代码如下:

public function AddNewPart(Request $request)
{
    if (array_key_exists('DrawingFile',$data)) {
        foreach($request->file('DrawingFile') as $key=>$file)
        {
            if ($data['fileupload_ID'][$key]==NULL) {
                $extension=$file->getClientOriginalExtension();
                $file_name2 = $file->getClientOriginalName();
                $filepath='Drawings/'.$data['PartNumber'].'/'.$data['Type'][$key].'/'.$file_name2;
                $file->move(public_path('Drawings/'.$data['PartNumber'].'/'.$data['Type'][$key].'/'), $file_name2);
                $DocumentData2=array('Type'=>$data['Type'][$key],'fcontent'=>$file_name2,'condpartno'=>$data['PartNumber'],'fname'=>$filepath,
                'DrawingNo'=>$data['DrawingNo'][$key],'DocumentType'=>$data['Type'][$key]);
                DB::table('fileupload')->insert($DocumentData2);
            }
        }
    }
}

请问如何实现上述重复文件的检测?


解决方案

要实现Drawings目录下全局的同名同扩展名文件检测,需要从数据库记录检查和实际文件系统检查两方面入手,避免出现数据库无记录但文件已存在、或数据库有记录但文件丢失的不一致情况:

1. 数据库层面检测

你已将文件信息存入fileupload表,其中fcontent字段存储完整文件名(含扩展名),可直接通过该字段查询是否存在同名文件:

// 在获取$file_name2后添加检测逻辑
$file_name2 = $file->getClientOriginalName();

// 检查数据库中是否已存在同名文件
$existsInDb = DB::table('fileupload')
    ->where('fcontent', $file_name2)
    ->exists();

if ($existsInDb) {
    // 返回错误提示,可根据需求调整返回逻辑
    return back()->withErrors(['DrawingFile['.$key.']' => '文件 '.$file_name2.' 已存在,请勿重复上传']);
}

2. 文件系统层面检测

如果存在数据库记录丢失但实际文件仍在的情况,需要递归遍历Drawings目录下所有子目录,检查是否有同名文件,可使用Laravel的File门面实现:

use Illuminate\Support\Facades\File;

// 获取Drawings根目录的绝对路径
$drawingsRoot = public_path('Drawings');

// 递归查找所有同名文件
$matchingFiles = File::glob($drawingsRoot.'/**/'.$file_name2);

if (!empty($matchingFiles)) {
    // 文件已存在,返回错误提示
    return back()->withErrors(['DrawingFile['.$key.']' => '文件 '.$file_name2.' 已存在,请勿重复上传']);
}

3. 整合后的完整处理函数

将检测逻辑放在文件移动和数据库插入之前,同时增加目录创建的容错处理:

public function AddNewPart(Request $request)
{
    if (array_key_exists('DrawingFile',$data)) {
        foreach($request->file('DrawingFile') as $key=>$file)
        {
            if ($data['fileupload_ID'][$key]==NULL) {
                $extension=$file->getClientOriginalExtension();
                $file_name2 = $file->getClientOriginalName();

                // 数据库重复检测
                $existsInDb = DB::table('fileupload')
                    ->where('fcontent', $file_name2)
                    ->exists();
                if ($existsInDb) {
                    return back()->withErrors(['DrawingFile['.$key.']' => '文件 '.$file_name2.' 已存在']);
                }

                // 文件系统重复检测
                $drawingsRoot = public_path('Drawings');
                $matchingFiles = File::glob($drawingsRoot.'/**/'.$file_name2);
                if (!empty($matchingFiles)) {
                    return back()->withErrors(['DrawingFile['.$key.']' => '文件 '.$file_name2.' 已存在']);
                }

                // 确保目标目录存在,避免文件移动失败
                $targetDir = public_path('Drawings/'.$data['PartNumber'].'/'.$data['Type'][$key].'/');
                if (!File::exists($targetDir)) {
                    File::makeDirectory($targetDir, 0755, true);
                }

                // 执行文件移动和数据库插入
                $filepath='Drawings/'.$data['PartNumber'].'/'.$data['Type'][$key].'/'.$file_name2;
                $file->move($targetDir, $file_name2);
                
                $DocumentData2=array(
                    'Type'=>$data['Type'][$key],
                    'fcontent'=>$file_name2,
                    'condpartno'=>$data['PartNumber'],
                    'fname'=>$filepath,
                    'DrawingNo'=>$data['DrawingNo'][$key],
                    'DocumentType'=>$data['Type'][$key]
                );
                DB::table('fileupload')->insert($DocumentData2);
            }
        }
    }
    return back()->with('success', '文件上传成功');
}

额外优化建议

  • 若Drawings目录下文件数量极大,递归查找会影响性能,可给fileupload表的fcontent字段添加唯一索引,强制数据库层面阻止重复插入,同时配合后台定期任务校验文件系统与数据库的一致性。
  • 可在前端上传前调用接口做一次文件名预检测,提升用户体验,避免上传后才提示错误。

内容的提问来源于stack exchange,提问作者Raginee Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:37:39