Laravel 5 Mime 验证

Posted

技术标签:

【中文标题】Laravel 5 Mime 验证【英文标题】:Laravel 5 Mime validation 【发布时间】:2015-07-02 18:29:55 【问题描述】:

好的,我正在尝试上传视频,并验证文件类型。

根据文档:

mimes:foo,bar,...

正在验证的文件必须具有与列出的扩展名之一相对应的 MIME 类型。

MIME 规则的基本用法

'照片' => 'mimes:jpeg,bmp,png'

我正在上传一个 wmv 视频,我的规则是这样的:

return [
    'file' => ['required', 'mimes:video/x-ms-wmv']
]

我在Request::file('file') 上做了一个print_r(),我得到了以下数据:

Symfony\Component\HttpFoundation\File\UploadedFile Object
(
    [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 
    [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => SampleVideo.wmv
    [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => video/x-ms-wmv
    [size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 70982901
    [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
    [pathName:SplFileInfo:private] => C:\wamp\tmp\php6428.tmp
    [fileName:SplFileInfo:private] => php6428.tmp
)

但是我得到了错误:

"file":["The file must be a file of type: video\/x-ms-wmv."]

我尝试将“mime 类型”更改为 video/*wmv(根据文档)以及 video/x-ms-wmv,但它们都没有正确验证文件。

print_r() 中可以看出,Symfony 的 MIME 类型变得 video/x-ms-wmv

我做错了吗?或者 Laravel/Symfony 不能很好地验证文件?

感谢您的帮助

编辑 好的,我打开validator.php并在ValidateMimes()方法中添加了echo $value->guessExtension();,它输出了asf。

为什么 Symfony 输出 video\x-ms-wmv,文件扩展名是 wmv,我正在验证它们,但 Laravel 猜测 asf?!

视频验证对我来说太不可靠了。

【问题讨论】:

我也遇到了这个问题,问题出在我使用的 PHP 版本上,尝试创建一个 vanilla php 文件并使用 Fileinfo 函数检查视频的 mime 类型php.net/manual/en/book.fileinfo.php 【参考方案1】:

这是预期的行为。

Laravel is 在 Symphony 的 UploadedFile 对象上调用 guessExtension,这将返回文件的预期扩展名,而不是 mimetype。

这就是为什么文档说明您应该使用上传的图片:

'照片' => 'mimes:jpeg,bmp,png'

Symfony 的 guessExtension 调用 getMimeType,它使用 PHP 的 Fileinfo Functions 去猜测给定文件的 mimetype。

一旦getMimeType 猜测文件的mimetype,Symfony 的MimeTypeExtensionGuesser 就会从文件中检索的mime 类型中获取扩展名。

    // ... cut from MimeTypeExtensionGuesser
    'video/x-ms-asf' => 'asf',
    'video/x-ms-wmv' => 'wmv',
    'video/x-ms-wmx' => 'wmx',
    'video/x-ms-wvx' => 'wvx',
    'video/x-msvideo' => 'avi',

因此,您的规则应该是:

return [
    'file' => ['required', 'mimes:wmv,asf']
]

应该包含asf 的原因主要是历史原因。引用***:

ASF 文件中最常见的媒体是 Windows Media Audio (WMA) 和 Windows Media Video (WMV)。 ASF 文件最常见的文件扩展名是扩展名 .WMA(使用 Windows Media Audio 的纯音频文件,MIME 类型为“audio/x-ms-wma”)和 .WMV(包含视频的文件,使用 Windows Media 音频和视频编解码器,使用MIME 类型“video/x-ms-asf”)。这些文件与旧的 .ASF 文件相同,但扩展名和 MIME 类型不同。

Microsoft 的文档关于 the difference between ASF and WMV/WMA files 状态:

ASF 文件与 WMV 或 WMA 文件之间的唯一区别是文件扩展名和 MIME 类型 [...] 文件的基本内部结构是相同的。

因为文件的内部结构是相同的(包括文件格式的magic numbers),所以wmv、wma和asf是一回事。这三个扩展程序之间的唯一区别是在 Explorer 中显示的图标。

不仅仅是 Windows Media 文件会出现此问题,Wikipedia lists 许多不同的视频容器格式也会出现同样的问题。如果您想查找容器中使用的视频编解码器,您需要查看的不仅仅是 fileinfo 函数使用的 "magic patterns"。 p>


话虽如此,预期的行为!= 正确的行为

我提交了一个pull request 来添加一个名为mimetypes 的新验证器。这正如您所期望的那样,并使用猜测的 mimetype 来验证上传的文件,而不是从 mimetype 中猜测的扩展名。

【讨论】:

感谢您的解释,您知道我是否只是不幸选择了“困难”文件类型(wmv/asf),还是其他文件类型也会出现这种情况(也就是说,我希望它是 mp4,但它“猜测”另一个扩展名,例如)? @PhilCross,主要是 WMV/ASF 有这个问题。 mp4 经历了一个更好的标准化过程 :) (虽然,您可能仍然会遇到 .mpv 文件被标记为 mp4 等的问题,但这是可以预料的 - 即,您希望将 jpeg 文件标记为 @ 987654343@等)。 wmv的问题在于它是一个容器格式,就像mkv一样,所以仅仅因为它最后有“.wmv”,并不意味着它确实使用Windows Media Video格式。 感谢您的再次解释!我会 +1 答案:) Laravel 中的字体怎么样?我对字体使用请求验证,但它不起作用! 'fontwoff2colum' => 'mimes:woff2' @FaridVatani mimetype应该application/font-woff。见github.com/symfony/mime/blob/master/MimeTypes.php

以上是关于Laravel 5 Mime 验证的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 可以验证 markdown mime 类型吗?

如果文件在 laravel 中上传,则文件 mime 类型验证

Laravel Mime 类型验证(KML 文件)

验证 .csv 文件时出现 Laravel MIME 问题

Laravel MIME 验证不适用于 .doc 文件

Laravel 5 - 从文件扩展名中获取 MIME 类型