1Uploading Files
2===============
3
4Ah yes, the good old problem of file uploads.  The basic idea of file
5uploads is actually quite simple.  It basically works like this:
6
71. A ``<form>`` tag is marked with ``enctype=multipart/form-data``
8   and an ``<input type=file>`` is placed in that form.
92. The application accesses the file from the :attr:`~flask.request.files`
10   dictionary on the request object.
113. use the :meth:`~werkzeug.datastructures.FileStorage.save` method of the file to save
12   the file permanently somewhere on the filesystem.
13
14A Gentle Introduction
15---------------------
16
17Let's start with a very basic application that uploads a file to a
18specific upload folder and displays a file to the user.  Let's look at the
19bootstrapping code for our application::
20
21    import os
22    from flask import Flask, flash, request, redirect, url_for
23    from werkzeug.utils import secure_filename
24
25    UPLOAD_FOLDER = '/path/to/the/uploads'
26    ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
27
28    app = Flask(__name__)
29    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
30
31So first we need a couple of imports.  Most should be straightforward, the
32:func:`werkzeug.secure_filename` is explained a little bit later.  The
33``UPLOAD_FOLDER`` is where we will store the uploaded files and the
34``ALLOWED_EXTENSIONS`` is the set of allowed file extensions.
35
36Why do we limit the extensions that are allowed?  You probably don't want
37your users to be able to upload everything there if the server is directly
38sending out the data to the client.  That way you can make sure that users
39are not able to upload HTML files that would cause XSS problems (see
40:ref:`security-xss`).  Also make sure to disallow ``.php`` files if the server
41executes them, but who has PHP installed on their server, right?  :)
42
43Next the functions that check if an extension is valid and that uploads
44the file and redirects the user to the URL for the uploaded file::
45
46    def allowed_file(filename):
47        return '.' in filename and \
48               filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
49
50    @app.route('/', methods=['GET', 'POST'])
51    def upload_file():
52        if request.method == 'POST':
53            # check if the post request has the file part
54            if 'file' not in request.files:
55                flash('No file part')
56                return redirect(request.url)
57            file = request.files['file']
58            # If the user does not select a file, the browser submits an
59            # empty file without a filename.
60            if file.filename == '':
61                flash('No selected file')
62                return redirect(request.url)
63            if file and allowed_file(file.filename):
64                filename = secure_filename(file.filename)
65                file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
66                return redirect(url_for('download_file', name=filename))
67        return '''
68        <!doctype html>
69        <title>Upload new File</title>
70        <h1>Upload new File</h1>
71        <form method=post enctype=multipart/form-data>
72          <input type=file name=file>
73          <input type=submit value=Upload>
74        </form>
75        '''
76
77So what does that :func:`~werkzeug.utils.secure_filename` function actually do?
78Now the problem is that there is that principle called "never trust user
79input".  This is also true for the filename of an uploaded file.  All
80submitted form data can be forged, and filenames can be dangerous.  For
81the moment just remember: always use that function to secure a filename
82before storing it directly on the filesystem.
83
84.. admonition:: Information for the Pros
85
86   So you're interested in what that :func:`~werkzeug.utils.secure_filename`
87   function does and what the problem is if you're not using it?  So just
88   imagine someone would send the following information as `filename` to
89   your application::
90
91      filename = "../../../../home/username/.bashrc"
92
93   Assuming the number of ``../`` is correct and you would join this with
94   the ``UPLOAD_FOLDER`` the user might have the ability to modify a file on
95   the server's filesystem he or she should not modify.  This does require some
96   knowledge about how the application looks like, but trust me, hackers
97   are patient :)
98
99   Now let's look how that function works:
100
101   >>> secure_filename('../../../../home/username/.bashrc')
102   'home_username_.bashrc'
103
104We want to be able to serve the uploaded files so they can be downloaded
105by users. We'll define a ``download_file`` view to serve files in the
106upload folder by name. ``url_for("download_file", name=name)`` generates
107download URLs.
108
109.. code-block:: python
110
111    from flask import send_from_directory
112
113    @app.route('/uploads/<name>')
114    def download_file(name):
115        return send_from_directory(app.config["UPLOAD_FOLDER"], name)
116
117If you're using middleware or the HTTP server to serve files, you can
118register the ``download_file`` endpoint as ``build_only`` so ``url_for``
119will work without a view function.
120
121.. code-block:: python
122
123    app.add_url_rule(
124        "/uploads/<name>", endpoint="download_file", build_only=True
125    )
126
127
128Improving Uploads
129-----------------
130
131.. versionadded:: 0.6
132
133So how exactly does Flask handle uploads?  Well it will store them in the
134webserver's memory if the files are reasonably small, otherwise in a
135temporary location (as returned by :func:`tempfile.gettempdir`).  But how
136do you specify the maximum file size after which an upload is aborted?  By
137default Flask will happily accept file uploads with an unlimited amount of
138memory, but you can limit that by setting the ``MAX_CONTENT_LENGTH``
139config key::
140
141    from flask import Flask, Request
142
143    app = Flask(__name__)
144    app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000
145
146The code above will limit the maximum allowed payload to 16 megabytes.
147If a larger file is transmitted, Flask will raise a
148:exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception.
149
150.. admonition:: Connection Reset Issue
151
152    When using the local development server, you may get a connection
153    reset error instead of a 413 response. You will get the correct
154    status response when running the app with a production WSGI server.
155
156This feature was added in Flask 0.6 but can be achieved in older versions
157as well by subclassing the request object.  For more information on that
158consult the Werkzeug documentation on file handling.
159
160
161Upload Progress Bars
162--------------------
163
164A while ago many developers had the idea to read the incoming file in
165small chunks and store the upload progress in the database to be able to
166poll the progress with JavaScript from the client. The client asks the
167server every 5 seconds how much it has transmitted, but this is
168something it should already know.
169
170An Easier Solution
171------------------
172
173Now there are better solutions that work faster and are more reliable. There
174are JavaScript libraries like jQuery_ that have form plugins to ease the
175construction of progress bar.
176
177Because the common pattern for file uploads exists almost unchanged in all
178applications dealing with uploads, there are also some Flask extensions that
179implement a full fledged upload mechanism that allows controlling which
180file extensions are allowed to be uploaded.
181
182.. _jQuery: https://jquery.com/
183