Where to Upload Python Files to Run Always
Writing a multi-file-upload Python-web app with user authentication
Providing an piece of cake method for collaborators to upload files to a filestore without the demand for them to empathise any lawmaking whatsoever
When building a webserver we ofttimes wish to present an idea or topic. In the case of a static website, this tin can exist done by including the relevant information inside the source files. In more dynamic examples, an API (awarding programming interface) tin can be used to pre-procedure information before returning it to the user.
In this example, we design a simple flask app which but requires a user key and a web browser to work. The idea backside this is that anyone tin can use it, and it is a device (and operating system), contained.
Creating the flask app
As usual, we start by installing the relevant libraries for the server. The simplest style to do this is through the use of pip (pythons packet manager).
pip install flask, werkzeug
The upload-page template
Next, create our HTML template for the login page. To do this we first in our awarding directory and make a new file named templates
. Inside this, we create a file named upload.html
and paste the following lawmaking 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 wait equally follows
Setting up the upload options
Next, we define a config file for our upload options. To practice this create a file named config.py
in your main app folder. Inside this, nosotros tin can specify a maximum accustomed file size, the upload destination, and what file extensions we can cull to take. Re-create the lawmaking below into config.py
and conform accordingly.
A note on file types: File extensions exercise not guarantee file type and we should avoid executing any uploaded files. This is why we later introduce a password — such that just canonical users can upload.
A flask template
Nosotros brainstorm with a bones flask template, which imports our information and serves the upload.html
folio when navigating to http://127.0.0.1:4000/upload
Upload file checks
Now we take 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 besides check the file extensions (again divers 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.road
sections within the code.
What to do on upload
Finally, nosotros have yet to tell the programme what to exercise upon uploading. Nosotros practice so this by parsing the post request from the upload folio. For information on what this means — have a read of:
Here we check if the request.method
is a POST, and if and then handle whatever files attached. The offset section deals with an empty request, whilst the second iterates through each file, checks that they have the right file extension, and if so saves them to our desired location (upload_dest
).
@app.route('/upload', methods=['Post'])
def upload_file():
if request.method == 'Post': if 'files[]' not in request.files:
flash('No files establish, 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.bring together( upload_dest, filename)) flash('File(due south) uploaded')
return redirect('/upload')
Testing the usage instance
Finally, earlier continuing on to adding passwords, we want to make sure that the upload functions as intended. To practise this we run the python script, navigate to http://127.0.0.ane:4000/upload, select a few files and click upload. If this has been successful, and you are using the configuration higher up, your files should now reside inside an uploads_folder
directory nested in the same folder as your app.
Adding an encrypted database for user authentication
And then far we accept created a Flask app which we tin can utilize to upload files. Next, we want to add a layer of bones security, such that we can track what files have been uploaded and past whom. In addition, this allows us to reject anyone not authorised to commit data to the directory.
Installing pysqlcipher3
We begin by installing our database tool. This tin can sometimes cause problems for people, and then the installation instructions for Mac and Linux have been included below.
MAC
brew install SQLCipher
pip install pysqlcipher3
LINUX
sudo apt install sqlcipher libsqlcipher0 libsqlcipher-dev
sudo -H pip3 install pysqlcipher3 python3 -c 'import pysqlcipher3; print(pysqlcipher3.__path__)'
Connecting to the database
Nosotros start by connecting to the database. If you have ever used databases earlier, the pysqlcipher syntax is pretty much the same as sqlite, or any postgresql libraries. We brainstorm by importing the libraries
from pysqlcipher3 import dbapi2 as sqlite3
from config import app_key, db_loc
And and so connecting to the database:
conn = sqlite3.connect(db_loc)# where this is /path/exam.db
cursor = conn.cursor()
Finally, we need to specify an encryption fundamental for our database in order to exist able to access the data.
cursor.execute("PRAGMA key='%s'"%app_key)
If you practice not practice this, or use a unlike cardinal, you will receive the following fault: DatabaseError: file is not a database
when trying to read information from the database schema.
Creating the Database
Having opened our database, and entered our primal, we tin now create a tabular array to store our values. Nosotros do this by executing a create table
SQL control with the cursor execute
function. The simplest usage case would require a name and an upload_key.
cursor.execute(
'''
CREATE TABLE IF NOT EXISTS upload (
id INTEGER Non Nothing PRIMARY Central AUTOINCREMENT,
name TEXT NOT NULL,
upload_key TEXT UNIQUE
);
'''
)
Additionally, I have set a status that each key has to be unique, as nosotros are not using a user name to log on.
Finally, nosotros have to commit our new table to the database and close it.
conn.commit()
## conn.close()
## shut only when we accept finished everything, otherwise we have to reopen the database each fourth dimension
Adding a User
We need users to be able to utilize the upload tool, so we can add together some using the insert
command.
cursor.execute(
'''
INSERT INTO upload (name, dir, uploadcode)
VALUES ("bob", "bobs top secret upload central")
'''
conn.commit()
Reading the Database
As a check, nosotros want to see if at that place is a proper name associated with the upload_key. This can exist washed with the select
role, coupled with a where
provisional.
user_code = 'bobs height secret upload central' cursor.execute('select * from upload where uploadcode="%s"'%user_code) result = cursor.fetchall() # go all the results east.k. [("bob",)]
Stringing it all together
Now we accept a database and an upload script, we can combine the 2.
Opening the database
Firstly we add the required library
from pysqlcipher3 import dbapi2 equally sqlite3
# from config import app_key, db_loc # already imported
under the from config_simple import *
line.
Reading the password
If you are using the HTML lawmaking from earlier, we already have a countersign input field :<p> upload_key: <input name="psw" type="password" /></p>
As this is inside the submission form nosotros can read information technology equally part of the POST request in the @app.road
wrapper.
user_code = str(asking.form.get('psw'))
Nosotros combine this with our database read to grade a provisional checking if there is anyone with that access cardinal /countersign.
cursor.execute('select * from upload where uploadcode="%s"'%user_code)
result = cursor.fetchall() if len(event)==0:
flash('Not a valid Code')
return redirect(request.url)
Still, since the database can only be opened and read from the same computational thread as the website nosotros need to place
conn = sqlite3.connect(db_loc)
cursor = conn.cursor()
cursor.execute("PRAGMA primal='%south'"%app_key)
before the cursor.execute
block, and a conn.shut()
subsequently the result =
line. (see app.py in the GitHub repo at the end)
Conclusion
And there nosotros have it — the most basic of submission boxes which allows for the uploading of files past pre-approved users. In that location are nonetheless a number of improvements that you may wish to make (these are all in the additional files shown in the GitHub repository beneath).
- Checking the filename string for an extension can cause problems. Files may be named incorrectly, or even non accept an extension (every bit was the instance with many of my files). Instead, nosotros can filter on the
file.mimetype
values. These are of the formatparadigm/png
etc. - Elevate and Drib uploading. It can ofttimes be cumbersome to manually select files, especially if they are in different locations. Dragging them from a file browser makes life much simpler for the user.
- Automatic uploads. Another common mistake is to select a file, but forget to click submit. Having a window that works immediately subsequently you drop a file in it tin aid aid productivity and user satisfaction
- File previews. If the user is uploading images, it tin can always be helpful to accept miniature previews available. This allows a last-minute cheque such that you are non repeatedly submitting the same file.
- File failure indicators. Although there is a message informing united states of america of the upload condition, a visual cue (ie a lighter preview image) makes information technology much easier to see if something has not worked.
- Unique download spaces — if you take many users, it can go disruptive which file belongs to who (non to mention the overwriting problem). Instead, we can add a designated infinite for each user, and save the paths within the database.
Adding all the boosted suggestions above and we the following output.
Hither nosotros see, two files have failed, with ane succeeding in the heart. In this case, it was due to invalid user credentials and an intentionally invalid filetype.
Disclaimer: this is not the near secure method of checking credentials, however for the purposes of many tasks information technology tin can be a perfectly adequate solution.
Codebase
All the example code for this tutorial has been dumped (quite literally) into a Github repository.
If you accept any improvements, feel free to submit a pull request.
Source: https://towardsdatascience.com/writing-a-multi-file-upload-python-web-app-with-user-authentication-8f75064b819a
0 Response to "Where to Upload Python Files to Run Always"
Post a Comment