使用 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-stream
在code
上描述得更好
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
为了解决这个问题,我必须实例化一个魔法对象并使用uncompressed
和mime
属性。完成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】:您不应依赖提供的 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” 选择第二个选项。【参考方案3】:最简单的判断方法是通过读取文件头中的元数据来窥探文件内容。
在大多数文件中,该文件头通常存储在文件的开头,但在某些文件中,它可能位于其他位置。
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
提供某些文件以上是关于使用 django 表单检查文件类型:'application/octet-stream' 问题的主要内容,如果未能解决你的问题,请参考以下文章
Django Rest Framework - 提交的数据不是文件。检查表单上的编码类型