MIME 类型检测是检测一种文件的最佳方法吗?

Posted

技术标签:

【中文标题】MIME 类型检测是检测一种文件的最佳方法吗?【英文标题】:Is MIME type detection the best way to detect a kind of file? 【发布时间】:2012-04-21 01:42:35 【问题描述】:

我正在使用 php 制作一个只能允许 MP3 文件的上传表单。

上传完成后,我会分析文件以检查它是否真的是 MP3。第一步是检测 mime 类型为audio/mpeg。我使用库 finfo_file() 并且工作正常,只是在测试期间某些 MP3 文件被拒绝,因为它们的 MIME 类型结果为 application/octet-stream

我的问题是:

我的应用程序应该绝对拒绝那些 MP3 文件吗?他们实际上是在播放音频。 这个 MIME 类型是 MP3 有什么原因吗? 检测 MIME 类型是了解文件类型的最可靠方法吗?

【问题讨论】:

【参考方案1】:

如果您想要一种极其可靠的文件类型检测方法,而不仅仅信任客户端提供正确的 MIME 类型,请在 UNIX 上使用 file 实用程序。

$ file Black\ Sands\ 01\ Prelude.mp3
Black Sands 01 Prelude.mp3: Audio file with ID3 version 2.2.0, contains: MPEG ADTS, layer III, v1, 320 kbps, 44.1 kHz, Stereo

$ file homework/math475-hw8.docx
homework/math475-hw8.docx: Microsoft Word 2007+

在 PHP 中,您可以使用 exec 函数来调用它。

【讨论】:

这是一个我没有考虑过的选项.. 我无法测试,因为我在赢 有一个为win32编译的版本here。 file 命令和 PHP 的 finfo_file 函数使用相同的方法来确定 mime 类型(通常通过引用 /usr/share/misc/magic)。当你有一个内置函数时,exec file 是没有用的。但是,我有一个案例,finfo_filefile -I 都将.mp3 检测为application/octet-stream,而我希望它返回audio/mpeg。两者都失败了。但是,我认为这可以通过将改进的magic 文件的路径作为finfo_open 的第二个参数传递来解决。【参考方案2】:

除了 MIME 之外,最好的文件检测方法是使用“magic byte”或“magic number”方案。 Unix file(以及finfo_file)实际上使用“魔术字节”来执行此文件检测。所以,简而言之:是的。

不要太担心您的文件是什么样子,而更多地关心您可以用它做什么。只要能播放,文件应该没问题。

如果您真的想要做更多,您可以自己检查魔术字节。有a list of them here。

【讨论】:

这就是为什么使用 getid3() 类我得到“audio/mpeg”但使用 finfo_filei 在同一个文件上得到“application/octet-stream”.. 这有点奇怪.. 但即使文件是可播放的,如果结果具有不同的 mime 类型,出于安全原因它将被拒绝(除非我找到更好的方法).. 我想知道有多少 mp3 没有正确的 mime.. @enkore “我想知道有多少 mp3 没有正确的 mime” MIME 类型由客户端提供。它不是 mp3 文件本身固有的。【参考方案3】:

在大多数需要上传的应用程序中,我有时会根据预定义的 MIME 类型列表验证浏览器(客户端)传递的 MIME。这种方法一般假设如果发生了一些可疑的事情,而浏览器无法传达正在上传的文件的 MIME 类型,我现在可能不想费心处理它。

<?php

$valid_mp3_mimes = array(
    'audio/mpeg',
    'audio/x-mpeg',
    'audio/mp3',
    'audio/x-mp3',
    'audio/mpeg3',
    'audio/x-mpeg3',
    'audio/x-mpeg-3',
    'audio/mpg',
    'audio/x-mpg',
    'audio/x-mpegaudio',
    'video/mpeg',
    'video/x-mpeg',
);

$uploaded_file_mime = $_FILES['upload_field_name']['type'];

if(!in_array($uploaded_file_mime, $valid_mp3_mimes))

    die('Upload is not a valid MP3 file.');

您可能会或可能不会觉得这足以满足您的目的。 PHP 手册明确指出,如果浏览器提供此信息,此信息可用,并且 MIME 类型未在服务器端检查,因此不应视为理所当然。

要考虑的一件事是服务器上允许您验证文件的真正 MIME 类型的资源的可用性。

作为 PHP 开发人员,我们喜欢在大多数情况下创建独立于平台的代码的灵活性(例如,我们在运行 XAMPP 的 Windows 系统上构建的 Web 应用程序可以部署到 Linux 托管环境,只需很少的修改)。但是,在验证 MIME 类型时,我们开始引入需要验证这些工具是否存在的平台相关方法(例如“file”或“finfo_file”)。

这可能是一个值得研究的实现(取自 CodeIgniter GitHub 存储库),它利用了这些工具,并且与 PHP 范围内的工作示例一样完整:

如果可能,文件 MIME 类型会检测上传文件的(实际)MIME 类型。 https://github.com/EllisLab/CodeIgniter/blob/develop/system/libraries/Upload.php#L983


来源

PHP 手册 POST 方法上传 - http://www.php.net/manual/en/features.file-upload.post-method.php

网站管理员工具包 Mime 类型 - http://www.webmaster-toolkit.com/mime-types.shtml

FILExt .MP3 文件 - http://filext.com/file-extension/MP3

【讨论】:

以上是关于MIME 类型检测是检测一种文件的最佳方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中检测上传文件的 MIME 类型

最佳 Mime 类型方法

检测从数据库中提取的文件的 MIME 类型

Codeigniter:在 mac safari 中未检测到 vcf mime 类型

Mime 类型检测在 PHP 5.3.8 上使用 fileinfo 失败

Rails -nokogiri GEM:检测 URL 中图像的 MIME 类型