.. _uploading-files:
Загрузка файлов
===============
Ну да, старая добрая проблема загрузки файлов. Основная мысль загрузки
файлов на самом деле очень проста. В общих чертах это работает так:
1. Тег ``
'''
Что делает функция :func:`~werkzeug.utils.secure_filename`? Мы исходим из
принципа "никогда не доверяй тому, что ввёл пользователь". Это справедливо
и для имени загружаемого файла. Все отправленные из формы данные могут
быть поддельными и имя файла может представлять опасность. Сейчас главное
запомнить: всегда используйте эту функцию для получения безопасного имени
файла, если собираетесь поместить файл прямо в файловую систему.
.. admonition:: Информация для профи
Может быть вам интересно, что делает функция
:func:`~werkzeug.utils.secure_filename` и почему нельзя обойтись без её
использования? Просто представьте, что кто-то хочет отправить следующую
информацию в ваше приложение в качестве имени файла::
filename = "../../../../home/username/.bashrc"
Если считать, что ``../`` - это нормально, то при соединении этого имени
с `UPLOAD_FOLDER`, пользователь может получить возможность изменять на
файловой системе сервера те файлы, который он не должен изменять. Нужно
немного разбираться в устройстве вашего приложения, но поверьте мне,
хакеры настойчивы :)
Посмотрим, как отработает функция:
>>> secure_filename('../../../../home/username/.bashrc')
'home_username_.bashrc'
Осталась последняя вещь: обслуживание загруженных файлов. Начиная с Flask
0.5 для этого можно использовать соответствующую функцию::
from flask import send_from_directory
@app.route('/uploads/')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
Другая возможность - зарегистрировать `uploaded_file` с помощью правила
`build_only` и воспользоваться :class:`~werkzeug.wsgi.SharedDataMiddleware`.
Такой вариант будет работать и в более старых версиях Flask::
from werkzeug import SharedDataMiddleware
app.add_url_rule('/uploads/', 'uploaded_file',
build_only=True)
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
'/uploads': app.config['UPLOAD_FOLDER']
})
Теперь, если запустить приложение, всё должно работать как положено.
Улучшение загрузки
------------------
.. versionadded:: 0.6
Как на самом деле Flask обрабатывает загрузку? Если файл достаточно мал,
он сохраняется в памяти веб-сервера. В противном случае он помещается во
временное место (туда, куда укажет :func:`tempfile.gettempdir`). Но как
указать максимальный размер файла, после которого загрузка файла должна
быть прервана? По умолчанию Flask не ограничивает размер файла, но вы
можете задать лимит настройкой ключа конфигурации ``MAX_CONTENT_LENGTH``::
from flask import Flask, Request
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
Код выше ограничит максимальный размер файла 16 мегабайтами. Если
передаваемый файл окажется больше, Flask сгенерирует исключение
:exc:`~werkzeug.exceptions.RequestEntityTooLarge`.
Эта функциональность была добавлена во Flask 0.6, но может быть реализована
и в более ранних версиях при помощи наследовании от класса request. За
более подробной информацией обратитесь к документации Werkzeug об обработке
файлов.
Индикаторы процесса загрузки
----------------------------
Многие разработчики придумывают считывать файл мелкими частями, сохранять
процент загрузки в базу данных и давать возможность JavaScript считывать
эти данные из клиента. Короче говоря, клиент спрашивает у сервера каждые
5 секунд, сколько уже было передано. Почувствовали иронию ситуации?
Клиент спрашивает у сервера о том, что уже и так знает.
Сейчас существуют способы получше, которые работают быстрее и более
надёжны. В последнее время в вебе многое изменилось и теперь можно
использовать HTML5, Java, Silverlight или Flash, чтобы сделать загрузку
удобнее со стороны клиента. Посмотрите на следующие библиотеки,
предназначенные именно для этого:
- `Plupload `_ - HTML5, Java, Flash
- `SWFUpload `_ - Flash
- `JumpLoader `_ - Java
Простейшее решение
------------------
Поскольку общая процедура загрузки файлов остаётся неизменной для всех
приложений, занимающихся загрузкой файлов, для Flask есть расширение под
названием `Flask-Uploads`_, которое реализует полностью самостоятельный
механизм загрузки с белым и чёрным списком расширений и т.п.
.. _Flask-Uploads: http://packages.python.org/Flask-Uploads/
`Оригинал этой страницы `_