Python:检查上传的文件是否为jpg

16

在Python(Google App Engine)中,我如何检查用户上传的文件是否为真正的jpg文件?

目前为止,我的进展如下:

脚本通过HTML表单POST接收图像,并由以下代码处理。

...
incomming_image = self.request.get("img")
image = db.Blob(incomming_image)
...

我找到了mimetypes.guess_type,但它对我没有用。

5个回答

37

如果您需要更多的内容而不仅仅是查看扩展名,一种方法是读取JPEG头部,并检查其是否匹配有效数据。格式如下:

Start Marker  | JFIF Marker | Header Length | Identifier
0xff, 0xd8    | 0xff, 0xe0  |    2-bytes    | "JFIF\0"

因此,一个快速的识别器可能是:

def is_jpg(filename):
    data = open(filename,'rb').read(11)
    if data[:4] != '\xff\xd8\xff\xe0': return False
    if data[6:] != 'JFIF\0': return False
    return True

然而,这不会捕获正文中的任何错误数据。如果您想进行更全面的检查,可以尝试使用PIL加载它。例如:

from PIL import Image
def is_jpg(filename):
    try:
        i=Image.open(filename)
        return i.format =='JPEG'
    except IOError:
        return False

第四个字节并不总是0xe0,0xe1也很常见,我相信还有其他可能性。 - hippietrail

34

无需使用和安装PIL库,可使用imghdr标准模块完美处理此类用途。

请参阅http://docs.python.org/library/imghdr.html

import imghdr

image_type = imghdr.what(filename)
if not image_type:
    print "error"
else:
    print image_type

如果您有来自流的图像,您可以使用流选项,可能是这样的:

image_type = imghdr.what(filename, incomming_image)

实际上这在我的Pylons中可以工作(即使我还没有完成所有内容): 在Mako模板中:

${h.form(h.url_for(action="save_image"), multipart=True)}
Upload file: ${h.file("upload_file")} <br />
${h.submit("Submit", "Submit")}
${h.end_form()}

在上传控制器中:

def save_image(self):
    upload_file = request.POST["upload_file"]
    image_type = imghdr.what(upload_file.filename, upload_file.value)
    if not image_type:
        return "error"
    else:
        return image_type

1
一个更通用的解决方案是使用Python绑定到Unix的“file”命令。为此,请安装python-magic包。示例:
import magic

ms = magic.open(magic.MAGIC_NONE)
ms.load()
type =  ms.file("/path/to/some/file")
print type

f = file("/path/to/some/file", "r")
buffer = f.read(4096)
f.close()

type = ms.buffer(buffer)
print type

ms.close()

0
JPEG文件规范的最后一个字节似乎不仅仅是e0。捕获前三个字节对于可靠地识别文件是否为JPEG来说已经足够了。请参见下面修改后的建议:
def is_jpg(filename):
    data = open("uploads/" + filename,'rb').read(11)
    if (data[:3] == "\xff\xd8\xff"):
        return True
    elif (data[6:] == 'JFIF\0'): 
        return True
    else:
        return False

0

使用PIL。如果它可以打开文件,那么它就是一张图片。

来自教程...

>>> import Image
>>> im = Image.open("lena.ppm")
>>> print im.format, im.size, im.mode

2
这在App Engine上行不通: PIL包含C代码,因此不可用。 Images API(http://code.google.com/appengine/docs/images/)使用PIL,但它被存根了。 - chryss

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