Our project uses Python 2.7, PIL 1.1.7 and Django 1.5.1. There is an ImageField which works OK for many image formats, including bmp, gif, ico, pnm, psd, tif and pcx. However the requirement is to only allow png or jpg images. How can it be done?
Upd. I know I can validate file extension and http Content-Type header. But neither method is reliable. What I'm asking is whether there's a way to check uploaded file content for being png/jpg.
You don't specify whether you're using a Django form to upload the image, I assume so as it is in the form field that the validation is carried out.
What you could do is create a subclass of django.forms.fields.ImageField
to extend the functionality of to_python.
The file type check currently carried out in Django in to_python
looks like this
Image.open(file).verify()
Your subclass could look something like.
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
You may notice this is most of the code from ImageField.to_python
and might prefer to just create a sub-class of FileField to use instead of ImageField
rather than subclassing ImageField
and duplicating much of its functionality. In this case make sure to add im.verify()
before the format check.
EDIT: I should point out that I've not tested this subclass.
You will probably want to use os for this. From the Python docs.
os.path.splitext(path) Split the pathname path into a pair (root, ext) such that root + ext == path, and ext is empty or begins with a period and contains at most one period. Leading periods on the basename are ignored; splitext('.cshrc') returns ('.cshrc', ''). Changed in version 2.6: Earlier versions could produce an empty root when the only period was the first character.
example
import os
fileName, fileExtension = os.path.splitext('yourImage.png')
print fileName
>>> "yourImage"
print fileExtension
>>> ".png"
So once you have your ext separated from the filename you should just use a simple string comparison to verify it's the right format.
You can use python-magic, a ctype wrapper around libmagic, the library used by the file
on Linux.
From its doc:
>>> 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'
However this method simply look at mime
information. You can still upload a non-valid PNG with the correct mime
or embed unauthorized data in file's metadata.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With