使用 django 形式检查文件类型:'application/octet-stream' 问题

Posted

技术标签:

【中文标题】使用 django 形式检查文件类型:\'application/octet-stream\' 问题【英文标题】:Checking file type with django form: 'application/octet-stream' issue使用 django 形式检查文件类型:'application/octet-stream' 问题 【发布时间】:2015-04-12 23:03:54 【问题描述】:

我正在使用 django 验证器和 python-magic 来检查上传文档的 mime 类型,并且只接受 pdf、zip 和 rar 文件。

接受的 mime 类型有: '申请/pdf', 'application/zip', 'multipart/x-zip', 'application/x-zip-compressed', 'application/x-compressed', 'application/rar', 'application/x-rar' 'application/x-rar-compressed', 'compressed/rar',

问题是有时 pdf 文件似乎将“应用程序/八位字节流”作为 mime 类型。 'application/octet-stream' 表示通用二进制文件,所以我不能简单地将该 mime 类型添加到接受的文件列表中,因为在这种情况下,也会接受其他文件,例如 es excel 文件,我不想要那会发生。

在这种情况下我该怎么办?

提前致谢。

【问题讨论】:

【参考方案1】:

作为Liyosi 答案的后续,我也使用了python-magic。 libmagic 似乎存在一个错误,它仍然错误地将某些文件标识为application/octet-streamcode上描述得更好

    def _handle509Bug(self, e):
        # libmagic 5.09 has a bug where it might fail to identify the
        # mimetype of a file and returns null from magic_file (and
        # likely _buffer), but also does not return an error message.
        if e.message is None and (self.flags & MAGIC_MIME):
            return "application/octet-stream"
        else:
            raise e

为了解决这个问题,我必须实例化一个魔法对象并使用uncompressedmime 属性。完成Liyosi 示例:

import magic
from django.core.exceptions import ValidationError

def validate_file_type(upload):
    allowed_filetypes = [
        'application/pdf', 'image/jpeg', 'image/jpg', 'image/png',
        'application/msword']
    validator = magic.Magic(uncompress=True, mime=True)
    file_type = validator.from_buffer(upload.read(), mime=True)
    if file_type not in allowed_filetypes:
        raise ValidationError('Unsupported file')

【讨论】:

【参考方案2】:

最简单的判断方法是通过读取文件头中的元数据来窥探文件内容。

在大多数文件中,该文件头通常存储在文件的开头,但在某些文件中,它可能位于其他位置。

python-magic 可以帮助您做到这一点,但诀窍是始终在文件开头重置指针,然后再尝试猜测其 mime 类型,否则有时您会得到 appliation/octet-stream mime 类型,如果阅读器的指针已经超过了文件头位置,到达了其他只包含任意字节流的位置。

例如,如果您有一个 django 验证器函数,它会尝试验证上传的文件的 mime 类型:

import magic
from django.core.exceptions import ValidationError

def validate_file_type(upload):
    allowed_filetypes = [
        'application/pdf', 'image/jpeg', 'image/jpg', 'image/png',
        'application/msword']
    upload.seek(0)
    file_type = magic.from_buffer(upload.read(1024), mime=True)
    if file_type not in allowed_filetypes:
        raise ValidationError(
            'Unsupported file')

【讨论】:

这仍然会为 appliation/octet-stream 提供某些文件【参考方案3】:

您不应依赖提供的 MIME 类型,而应依赖从文件本身的前几个字节中发现的 MIME 类型。

这将有助于消除通用 MIME 类型问题。

这种方法的问题在于它通常依赖于一些第三方工具(例如,Linux 系统上常见的file 命令非常棒;将它与-b --mime - 一起使用并传入你的前几个字节文件让它给你 MIME 类型)。

您的另一个选择是接受该文件,并尝试通过使用库打开它来验证它。

因此,如果pypdf 无法打开文件,而内置的zip 模块无法打开文件,而rarfile 无法打开文件 - 这很可能是您不想接受的情况。

【讨论】:

我不依赖提供的 MIME 类型。我已经阅读了前几个字节来发现它,使用 python-magic: mime = magic.from_buffer(value.read(1024), mime=True) 但这种方法有时也会给出“application/octet-stream” 选择第二个选项。

以上是关于使用 django 形式检查文件类型:'application/octet-stream' 问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用魔法来验证 Django 表单清理方法中的文件类型?

Django Rest Framework - 提交的数据不是文件。检查表单上的编码类型

快学Scala 第二课 (apply, if表达式,循环,函数的带名参数,可变长参数,异常)

收到错误:MIME 类型 ('text/html') 不是受支持的样式表 MIME 类型,并且使用 DJANGO PYTHON 启用了严格的 MIME 检查

SQL 关于apply的两种形式cross apply 和 outer apply

SQL 关于apply的两种形式cross apply 和 outer apply