【问题标题】:How to validate image format in django ImageField如何在 django ImageField 中验证图像格式
【发布时间】:2013-12-24 12:37:34
【问题描述】:

我们的项目使用 Python 2.7、PIL 1.1.7 和 Django 1.5.1。有一个 ImageField 适用于许多图像格式,包括 bmp、gif、ico、pnm、psd、tif 和 pcx。然而,要求是只允许 png 或 jpg 图像。怎么办?

更新。我知道我可以验证文件扩展名和 http Content-Type 标头。但是这两种方法都不可靠。我要问的是是否有办法检查上传的文件内容是否为 png/jpg。

【问题讨论】:

  • 我知道您可以在表单设置中进行一些验证。详细情况我会告诉你的。
  • 看到这个answer和这个link
  • 还有这个:django-vimage!

标签: python django python-imaging-library


【解决方案1】:

您没有指定是否使用 Django 表单来上传图像,我假设是在执行验证的表单字段中。

您可以做的是创建django.forms.fields.ImageField 的子类来扩展 to_python 的功能。

当前在to_python Django 中进行的文件类型检查是这样的

Image.open(file).verify()

您的子类可能看起来像这样。

class DmitryImageField(ImageField):

    def to_python(self, data):
        f = super(DmitryImageField, self).to_python(data)
        if f is None:
            return None

        try:
            from PIL import Image
        except ImportError:
            import Image

        # We need to get a file object for PIL. We might have a path or we might
        # have to read the data into memory.
        if hasattr(data, 'temporary_file_path'):
            file = data.temporary_file_path()
        else:
            if hasattr(data, 'read'):
                file = BytesIO(data.read())
            else:
                file = BytesIO(data['content'])

        try:
            im = Image.open(file)
            if im.format not in ('BMP', 'PNG', 'JPEG'):
                raise ValidationError("Unsupport image type. Please upload bmp, png or jpeg")
        except ImportError:
            # Under PyPy, it is possible to import PIL. However, the underlying
            # _imaging C module isn't available, so an ImportError will be
            # raised. Catch and re-raise.
            raise
        except Exception: # Python Imaging Library doesn't recognize it as an image
            raise ValidationError(self.error_messages['invalid_image'])

        if hasattr(f, 'seek') and callable(f.seek):
            f.seek(0)
        return f

您可能会注意到这是来自 ImageField.to_python 的大部分代码,并且可能更愿意只创建 FileField 的子类来代替 ImageField 而不是子类化 ImageField 并复制其大部分功能。在这种情况下,请务必在格式检查之前添加im.verify()

编辑:我应该指出我没有测试过这个子类。

【讨论】:

  • 谢谢!它对我有用(稍作修改)
  • 那个 try...except 块会捕捉到raise ValidationError,而且你可以通过clean_field 方法更容易地做到这一点。
  • 这是在 Django 的 ImageField 中发生的地方:github.com/django/django/blob/…
【解决方案2】:

您可能希望为此使用 os。来自 Python 文档。

os.path.splitext(路径) 将路径名路径拆分为一对 (root, ext),使得 root + ext == path,并且 ext 为空或以句点开头并且最多包含一个句点。基本名称上的前导句点被忽略; splitext('.cshrc') 返回 ('.cshrc', '')。 在 2.6 版中更改:当唯一的句点是第一个字符时,早期版本可能会产生一个空的根。

例子

import os
fileName, fileExtension = os.path.splitext('yourImage.png')

print fileName 
>>> "yourImage"

print fileExtension
>>> ".png"

因此,一旦您将 ext 与文件名分开,您就应该使用简单的字符串比较来验证它的格式是否正确。

【讨论】:

  • 感谢您的回答。然而,我要问的是我是否可以检查上传的文件内容是否为 png/jpg。检查文件扩展名是不可靠的。例如,我可以将 bmp 文件重命名为 png,然后上传。
  • 哦,所以不仅仅是一个扩展名,您要确保文件是扩展名应该是其中的内容。对不起,我误解了这个问题。
  • 大多数情况下,检查文件扩展名就足够了!
【解决方案3】:

您可以使用python-magic,它是一个围绕 libmagic 的 ctype 包装器,这是 Linux 上 file 使用的库。

来自其文档:

>>> import magic
>>> magic.from_file("testdata/test.pdf")
'PDF document, version 1.2'
>>> magic.from_buffer(open("testdata/test.pdf").read(1024))
'PDF document, version 1.2'
>>> magic.from_file("testdata/test.pdf", mime=True)
'application/pdf'

不过这个方法只看mime的信息。您仍然可以使用正确的mime 上传无效的 PNG,或在文件的元数据中嵌入未经授权的数据。

【讨论】:

    猜你喜欢
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2011-01-04
    • 2011-08-11
    • 2015-12-04
    • 2012-02-08
    相关资源
    最近更新 更多