БетаЛаборатория - внеочередной IT-блог

Записки обычного программиста

 

Записи с тэгом snippets

Хэширование имен загружаемых файлов в Django

Уже давно я столкнулся в Django с проблемой загрузки файлов, с utf8 символами в названии. При сохранении такого файла django рушилась с руганью на ошибку конвертации ascii строки. Однако тогда разбираться с проблемой я не стал за ненадобностью - мне было проще переименовывать редкие файлы с utf8 именами.
 
А вот сейчас проблема эта всплыла опять и достаточно остро. За советом как лучше поступать с utf8 в именах файлов я обратился к хорошему сисадмину, который посоветовал мне вообще отказаться от сохранения юникода. Это чревато рисками обхода ограничений директории и получения доступа к исполняемым файлам системы.
 
"Дело в том, что из-за отсутствия гарантий однообразности восприятия специальных символов в имени файла, одни функции в системе могут счесть имя файла валидным и безопасным, а другие - иначе интерпретировать некоторые символы, в результате чего есть опасность нарваться на "../../../filename" в аргументах системному вызову, со всеми вытекающими." © Arach
 
Поэтому, было решено просто хэшировать имена загружаемых файлов. Есть в этом конечно и минус (при скачивании файла несколько не удобно будет его идентифицировать), однако на данном этапе так будет лучше. А уж в процессе подумаю о решении и этой проблемы.
 
Изменить метод работы с файлами в Django очень просто - достаточно сделать специальный обработчик - подкласс django.core.files.storage.Storage. Мало того, в случае лишь частичной замены методов работы, можно наследовать стандартные дочерние классы.
 
# -*- coding: utf-8 -*-
from django.core.files.storage import FileSystemStorage
from hashlib import sha1

class SHA1FilenameFileSystemStorage(FileSystemStorage):
	def get_valid_name(self, name):
		type=""
		if name.rfind("."):
			type = name[name.rindex("."):]
		return str(sha1(name.encode("UTF-8")).hexdigest())+type
 
В данном случае я наследовал стандартный класс хранилища файлов FileSystemStorage, переопределив в нем всего один метод. Метод get_valid_name отвечает за генерацию валидного имени файла ДО проверки доступности такого имени для сохранения. Сначала мы пытаемся отделить расширение файла, если таковое есть, после чего хэшируем входящее имя и прибавляем к нему расширение. Лично я предпочел установить этот обработчик в качестве стандартного в своих приложениях, для чего в settings.py определяется переменная DEFAULT_FILE_STORAGE.
 
import django_useful
DEFAULT_FILE_STORAGE = 'django_useful.sha1storage.SHA1FilenameFileSystemStorage'
Если же надо применить данный обработчик только к определенным файлам, нужно в модели передать путь  его в качестве аргумента storage
 

from django.db import models
import django_useful

class Car(models.Model):
    photo = models.ImageField(storage=django_useful.sha1storage.SHA1FilenameFileSystemStorage(location='/media/photos'))
 
PS: Сегодня добавил в блог подсветку синтаксиса с помощью Pygments. Реализовал в виде плагина для FCKEditor, но пока не очень изящно - код со стилями и прочей ересью вставляется прямо в пост. Не очень удобно редактировать - фактически приходится заново генерировать код полностью. Думаю что лучше будет заменить это все на вставку некого плейсхолдера, и генерировать код непосредственно перед выводом, с помощью PreView триггера.

Авторизация

Логин:

Пароль:


Регистрация | Забыли пароль?


Последние записи


Promo

Follow pyhoster on Twitter Subscribe

Реклама

A Django project.