1 2 3 4
| public function index(Request $request) { return $request->file('file')->store('', 'public'); }
|
简单的文件上传其实就是上面的代码,但是有时候传一些 特殊 的文件会发现保存的扩展名会有问题。

这里我找了一个 apk
文件,上传后发现变成了 jar
文件。
通过源码发现调用 store
的时候会生成一个文件名,通过 finfo 去获取上传文件的后缀名。
vendor\symfony\http-foundation\File\MimeType\FileinfoMimeTypeGuesser.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public function guess($path) { if (!is_file($path)) { throw new FileNotFoundException($path); } if (!is_readable($path)) { throw new AccessDeniedException($path); } if (!self::isSupported()) { return; } if (!$finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { return; } return $finfo->file($path); }
|
验证下是不是真的是 finfo 的问题
1 2 3 4 5 6
| public function index(Request $request) { $finfo = new \finfo(FILEINFO_MIME_TYPE);
return $finfo->file($_FILES['file']['tmp_name']); }
|

解决方案:创建一个例外的 mime type 列表,然后我们判断上传文件的 mime type 在不在这个列表里面,如果在的话我们就根据这个 mime type 来获取后缀。
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
| <?php
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeExtensionGuesser; use Illuminate\Support\Str; use Illuminate\Http\Request;
class UploadController extends Controller { public function index(Request $request) { $exception_mime_type = [ 'application/vnd.android.package-archive', ];
$storage_disk = 'public';
$name = $request->query('name', 'file');
if(!$request->hasFile($name)) { return '未有文件上传'; }
$file = $request->file($name);
$mime_type = $file->getClientMimeType();
if(!in_array($mime_type, $exception_mime_type)) { return $file->store('', $storage_disk); }
$guesser = new MimeTypeExtensionGuesser;
$extension = $guesser->guess($mime_type);
$path = $file->storeAs( $storage_disk, Str::random(40) . '.' . $extension );
return $path; } }
|