Writing a multi-file-upload Python-web app with user authentication
By: Daniel Ellis
Tags: Encrypt, Database, Upload, Flask, Python

When building a webserver we often wish to present an idea or topic. In the case of a static website, this can be done by including the relevant information within the source files. In more dynamic examples, an API (application programming interface) can be used to pre-process information before returning it to the user.

In this example, we design a simple flask app which only requires a user key and a web browser to work. The idea behind this is that anyone can use it, and it is a device (and operating system), independent.

Creating the flask app

As usual, we start by installing the relevant libraries for the server. The simplest way to do this is through the use of pip (pythons package manager).

pip install flask, werkzeug

The upload-page template

Next, create our HTML template for the login page. To do this we start in our application directory and make a new file named templates . Within this, we create a file named upload.html and paste the following code within it.

In essence, we have a form which contains our password input , a file upload input and a submit button. When working this will look as follows

Output from upload_simple.html

Setting up the upload options

Next, we define a config file for our upload options. To do this create a file named config.py in your main app folder. Within this, we can specify a maximum accepted file size, the upload destination, and what file extensions we can choose to accept. Copy the code below into config.py and adjust accordingly.

A note on file types: File extensions do not guarantee file type and we should avoid executing any uploaded files. This is why we later introduce a password — such that only approved users can upload.

A flask template

We begin with a basic flask template, which imports our information and serves the upload.html page when navigating to http://127.0.0.1:4000/upload

Upload file checks

Now we have our app, we can add a number of functions to ensure that we have the correct directory, and if not create it.

if not os.path.isdir(upload_dest):

os.mkdir(upload_dest)

We can set the maximum file upload size (using the value from config.py )

app.config['MAX_CONTENT_LENGTH'] = file_mb_max * 1024 * 1024

and also check the file extensions (again defined in config.py )

def allowed_file(filename):

return '.' in filename and filename.rsplit('.', 1)[1].lower() in extensions

Personally, I have added these between app.secret and the @app.route sections within the code.

What to do on upload

Finally, we have yet to tell the program what to do upon uploading. We do so this by parsing the post request from the upload page. For information on what this means — have a read of:

Here we check if the request.method is a POST, and if so handle any files attached. The first section deals with an empty request, whilst the second iterates through each file, checks that they have the correct file extension, and if so saves them to our desired location ( upload_dest ).



def upload_file():

if request.method == 'POST': @app .route('/upload', methods=['POST'])def upload_file():if request.method == 'POST': if 'files[]' not in request.files:

flash('No files found, try again.')

return redirect(request.url) files = request.files.getlist('files[]') for file in files:

if file and allowed_file(file.filename):

filename = secure_filename(file.filename)

file.save(os.path.join( upload_dest, filename)) flash('File(s) uploaded')

return redirect('/upload')

Testing the usage case