检测 MIME 类型是检测文件类型的最佳方式吗?

8

我正在使用PHP编写上传表单,只允许上传MP3文件。

上传完成后,我会分析文件以检查它是否真的是MP3格式。第一步是检测MIME类型为audio/mpeg。我使用finfo_file()库进行检测,虽然在测试中有些MP3文件被拒绝,因为它们的MIME类型结果为application/octet-stream

我的问题是:

  • 我的应用程序是否应该拒绝这些MP3文件?实际上它们可以播放音频。
  • 为什么这个MIME类型会是MP3?
  • 检测MIME类型是确定文件类型的最可靠方法吗?
3个回答

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/zh/features.file-upload.post-method.php

Webmaster Toolkit MIME类型 - http://www.webmaster-toolkit.com/mime-types.shtml

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


0
如果您想要一种非常强大的检测文件类型的方法,而不仅仅是依赖客户端提供正确的 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 函数调用它。

这是一个我没有考虑过的选项..而且我无法测试,因为我在Windows系统上。 - enkore
这里有一个为win32编译的版本链接 - Rag
1
file 命令和 PHP 的 finfo_file 函数使用相同的方法来确定 MIME 类型(通常是通过引用 /usr/share/misc/magic)。当您有内置函数时,执行 exec file 就没有用了。然而,我在这里遇到了一个问题,即 .mp3finfo_filefile -I 都检测为 application/octet-stream,而我希望它返回 audio/mpeg。两者都失败了。但是,我认为可以通过将改进后的 magic 文件的路径作为第二个参数传递给 finfo_open 来解决这个问题。 - Quinn Comendant

0

文件检测的最佳方法是使用“魔术字节”或“魔数”方案,以及MIME。Unix file(以及finfo_file)实际上使用“魔术字节”来进行文件检测。所以,简而言之:是的。

不要太担心你的文件长什么样子,更关注你可以用它做什么。只要能播放,文件就应该没问题。

如果你真的想做更多,你可以自己检查魔术字节。这里有一个列表


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接