Reputation: 22747
I am using Pillow 2.3.0 with Django and I have an ImageField in my models.py like so:
class UserImages(models.Model):
user = models.ForeignKey(User)
photo = models.ImageField(upload_to=get_file_path)
and I have a form like so:
class UploadImageForm(forms.ModelForm):
class Meta:
model = UserImages
fields = ['photo']
How do I make it so that the UploadImageForm only accepts png's and jpeg's? What I tried is adding this clean method to the form:
def clean_photo(self):
photo = self.cleaned_data.get('photo', False)
if photo:
fileType = photo.content_type
if fileType in settings.VALID_IMAGE_FILETYPES: #png and jpeg
return photo
raise forms.ValidationError('FileType not supported: only upload jpegs and pngs.')
but according to this documentation (https://docs.djangoproject.com/en/1.5/topics/http/file-uploads/#uploadedfile-objects) it says that "You'll still need to validate that the file contains the content that the content-type header claims – 'trust but verify'." How do I verify that the user did infact upload the file type which he claimed to upload?
Upvotes: 2
Views: 4612
Reputation: 53669
The ImageField
validators already verify that the uploaded file is a valid image file supported by Pillow. This is enough to prevent any malicious code injection - the worst that can happen is that someone uploads a file with a different extension than its file format.
I generally don't verify if an uploaded image is indeed the format it portraits to be. As long as it is a valid image file, and the file extension is in my allowed extension, I accept the uploaded file.
You can, however, easily override the clean_photo
method to determine and verify the actual file type:
from django.utils.image import Image
def clean_photo(self):
photo = self.cleaned_data.get(['photo'])
if photo:
format = Image.open(photo.file).format
photo.file.seek(0)
if format in settings.VALID_IMAGE_FILETYPES:
return photo
raise forms.ValidationError(...)
The photo.file.seek(0)
part is important, without it you will run into problems when saving the file!!
Note that format
is not necessarily equal to the content type or the extension: in the case of .png
it is 'PNG'
, and in the case of .jpg
it's 'JPEG'
. I don't know if other formats follow suit; you'll have to test that for yourself.
Image.open
does not load the entire file content, just the header, so this method is quite fast. Using timeit
and a random .png
file, I've run the following code 1,000,000 times:
format = Image.open(g.photo).format
g.photo.seek(0)
The average time for this code was 0.0001 seconds, so yeah, lightning fast.
Upvotes: 6