1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| <?php
namespace App\Services;
use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str;
class SecureFileUploadService { protected array $allowedMimes = [ 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', ];
protected int $maxSize = 10485760;
protected array $dangerousExtensions = [ 'php', 'php3', 'php4', 'php5', 'phtml', 'exe', 'bat', 'cmd', 'sh', 'js', 'html', 'htm', ];
public function upload(UploadedFile $file, string $directory = 'uploads'): array { $this->validate($file);
$safeName = $this->generateSafeName($file); $path = $file->storeAs($directory, $safeName, 'local');
$this->scanFile($path);
return [ 'original_name' => $file->getClientOriginalName(), 'path' => $path, 'size' => $file->getSize(), 'mime_type' => $file->getMimeType(), 'hash' => md5_file($file->path()), ]; }
protected function validate(UploadedFile $file): void { if (!$file->isValid()) { throw new \Exception('文件上传失败'); }
if ($file->getSize() > $this->maxSize) { throw new \Exception('文件大小超出限制'); }
if (!in_array($file->getMimeType(), $this->allowedMimes)) { throw new \Exception('文件类型不允许'); }
$extension = strtolower($file->getClientOriginalExtension()); if (in_array($extension, $this->dangerousExtensions)) { throw new \Exception('危险的文件类型'); }
$this->validateFileContent($file); }
protected function validateFileContent(UploadedFile $file): void { $finfo = finfo_open(FILEINFO_MIME_TYPE); $actualMime = finfo_file($finfo, $file->path()); finfo_close($finfo);
if ($actualMime !== $file->getMimeType()) { throw new \Exception('文件类型验证失败'); } }
protected function generateSafeName(UploadedFile $file): string { $extension = $this->getSafeExtension($file); return Str::random(40) . '.' . $extension; }
protected function getSafeExtension(UploadedFile $file): string { $mimeToExt = [ 'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif', 'application/pdf' => 'pdf', ];
$mime = $file->getMimeType(); return $mimeToExt[$mime] ?? 'bin'; }
protected function scanFile(string $path): void { } }
|