Check Flask upload if user does not selected file - python

If user doesn't select a file in form (equals PHP UPLOAD_ERR_NO_FILE
), request.files['file'] also return a FileStorage object, I am using request.files['file'].filename == '' to check, any better way ? I have seen Flask Doc but can't find the answer.
'file' in request.files will not work on user doesn't select file, browser also will submit a 0 length and filename equals '' (empty string) part.
and how do I detect uploaded file was only partially uploaded error (equals PHP UPLOAD_ERR_PARTIAL) ?

Now I am using
if request.files['file'].filename == '':
return 'No selected file'
or using file length check
import os
file = request.files['file']
file.seek(0, os.SEEK_END)
if file.tell() == 0:
return 'No selected file'

Try:
if not request.files.get('file', None):
pass
If you want have most control over the files, you can use http://pythonhosted.org/Flask-Uploads/

import imghdr
def validate_image(stream):
header = stream.read(512)
stream.seek(0)
format = imghdr.what(None, header)
if not format:
return None
return '.'+format
class UploadFiles(Resource):
def post(self):
doc=request.files.get('image')
if validate_image(doc.stream):
print('file validated')

Related

Getting NULL data when uploading file to Sqlite DB [duplicate]

I am writing my first flask application. I am dealing with file uploads, and basically what I want is to read the data/content of the uploaded file without saving it and then print it on the resulting page. Yes, I am assuming that the user uploads a text file always.
Here is the simple upload function i am using:
#app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
file = request.files['file']
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
a = 'file uploaded'
return render_template('upload.html', data = a)
Right now, I am saving the file, but what I need is that 'a' variable to contain the content/data of the file .. any ideas?
FileStorage contains stream field. This object must extend IO or file object, so it must contain read and other similar methods. FileStorage also extend stream field object attributes, so you can just use file.read() instead file.stream.read(). Also you can use save argument with dst parameter as StringIO or other IO or file object to copy FileStorage.stream to another IO or file object.
See documentation: http://flask.pocoo.org/docs/api/#flask.Request.files and http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.
If you want to use standard Flask stuff - there's no way to avoid saving a temporary file if the uploaded file size is > 500kb. If it's smaller than 500kb - it will use "BytesIO", which stores the file content in memory, and if it's more than 500kb - it stores the contents in TemporaryFile() (as stated in the werkzeug documentation). In both cases your script will block until the entirety of uploaded file is received.
The easiest way to work around this that I have found is:
1) Create your own file-like IO class where you do all the processing of the incoming data
2) In your script, override Request class with your own:
class MyRequest( Request ):
def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
return MyAwesomeIO( filename, 'w' )
3) Replace Flask's request_class with your own:
app.request_class = MyRequest
4) Go have some beer :)
I share my solution (assuming everything is already configured to connect to google bucket in flask)
from google.cloud import storage
#app.route('/upload/', methods=['POST'])
def upload():
if request.method == 'POST':
# FileStorage object wrapper
file = request.files["file"]
if file:
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
bucket_name = "bucket_name"
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
# Upload file to Google Bucket
blob = bucket.blob(file.filename)
blob.upload_from_string(file.read())
My post
Direct to Google Bucket in flask
I was trying to do the exact same thing, open a text file (a CSV for Pandas actually). Don't want to make a copy of it, just want to open it. The form-WTF has a nice file browser, but then it opens the file and makes a temporary file, which it presents as a memory stream. With a little work under the hood,
form = UploadForm()
if form.validate_on_submit():
filename = secure_filename(form.fileContents.data.filename)
filestream = form.fileContents.data
filestream.seek(0)
ef = pd.read_csv( filestream )
sr = pd.DataFrame(ef)
return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form)
I share my solution, using pandas
#app.route('/upload/', methods=['POST'])
def upload():
if request.method == 'POST':
# FileStorage object wrapper
file = request.files["file"]
if file:
df = pd.read_excel(files_excel["file"])
Building on a great answer by #tbicr the simplest form of that boils down to:
for line in request.files.get('file'):
print("Next line: " + line)
in function
def handleUpload():
if 'photo' in request.files:
photo = request.files['photo']
if photo.filename != '':
image = request.files['photo']
image_string = base64.b64encode(image.read())
image_string = image_string.decode('utf-8')
#use this to remove b'...' to get raw string
return render_template('handleUpload.html',filestring = image_string)
return render_template('upload.html')
in html file
<html>
<head>
<title>Simple file upload using Python Flask</title>
</head>
<body>
{% if filestring %}
<h1>Raw image:</h1>
<h1>{{filestring}}</h1>
<img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
{% else %}
<h1></h1>
{% endif %}
</body>
In case we want to dump the in memory file to disk. This code can be used
if isinstanceof(obj,SpooledTemporaryFile):
obj.rollover()

Get MIME type of file that is in memory - Python Django

I have a form where users can upload files. I only want them to be able to upload images. I have added that in the HTML form but need to do a server side check. I would like to do this check before I save the file to AWS S3.
Currently I have this:
from .models import cropSession, cropSessionPhoto
import magic
def crop(request):
if request.method == 'POST':
data = request.POST
images = request.FILES.getlist('photos')
crop_style = data['style']
if len(images) <= 0:
messages.error(request, "At least one photo must be uploaded.")
return redirect(reverse('crop-form'))
crop_session = cropSession(crop_style=crop_style)
crop_session.save()
for image in images:
mime = magic.Magic(mime=True)
mime.from_file(image.file)
upload = cropSessionPhoto(crop_session=crop_session, photo_file_name=image, photo_file_location=image)
upload.save()
else:
messages.error(request, "An error has occured.")
return redirect(reverse('crop-form'))
return render(request, 'crop/crop.html')
However, I get this error:
TypeError: expected str, bytes or os.PathLike object, not BytesIO
How do I properly pass the image to magic?
Thank you
Magic expects the argument for from_file to be a path so it can open the file. If it's already in memory you can try opening it as a buffer:
mime = magic.Magic(mime=True)
mime.from_buffer(f.read(2048))

Flask / Python: #after_this_request is not accessed

I trying to delete a file I've created after it was displayed on the webservice.
However with the current placement of the function, it says 'remove_file(response) is not accessed' and when I run the webservice I get an error when outputting the file, as it apparently already has been deleted.
I don't know what to do anymore, I've tried placing the afer_this_request function right after the upload_file declaration, after the return render template, all of it never works. I'm going crazy, so any help would make my year!
#app.route('/', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
myuuid = uuid.uuid4()
# check if the post request has the file part
if 'file' not in request.files:
return render_template('error.html')
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
return render_template('error.html')
if file and allowed_file(file.filename):
sfilename = secure_filename(file.filename)
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.mkdir(app.config['UPLOAD_FOLDER'])
output_path = os.path.join(app.config['UPLOAD_FOLDER'], sfilename)
file.save(output_path)
if 'Alpha Miner' in request.form:
Alpha(pro_file, myuuid)
img_url = url_for('static', filename=str(myuuid) + '.gv.svg')
#after_this_request
def remove_file(response):
os.remove(img_url)
return response
titel = "Petri Net for Alpha Miner: " + sfilename
return render_template('upload.html', img_url=img_url, titel = title)
Try this :
file_handle = open(img_url, 'r')
#after_this_request
def remove_file(response):
try:
os.remove(img_url)
file_handle.close()
except Exception as error:
app.logger.error("Error removing or closing downloaded file handle", error)
return response

How is my filename referenced before assignment?

Whenever i try to run my code i get 'local variable 'filename' referenced before assignment'.
however in my app.route i define filename before i use it. How do I fix it?
here is the code that isnt working:
#app.route('/getfileHelper', methods=['GET','POST'])
def getfileHelper():
if request.method == 'POST':
file = request.files['imgfile']
filename = secure_filename(file.filename) #from werkzeug import secure_filename
if file.filename == '':
flash("No file selected. Please select an image file")
return render_template('selectImage.html')
texts = detect_text('static/images/'+filename)
text_translations = [] #emty list for dictionary of original text and translation
for text in texts:
translate_client = translate.Client() # Instantiates a client
translate_text = text.description # The text to translate
source = 'en' # The source language
target = request.args["lang_target"] # The target language
translation = translate_client.translate(translate_text, source_language=source, target_language=target)
text_translations.append({'text':translate_text, 'translation':translation['translatedText']})
db_append(filename, translate_text, translation['translatedText'])
return render_template('home.html', filename=filename, text_translations=text_translations)
return render_template('home.html', filename=filename, text_translations=text_translations)
Suppose that the input request.method == 'GET'. What do you expect the value of filename to be, and why? Where will that value come from? Solve that, and you solve the problem (except that the same problem also applies to text_translations). I can't be more specific, because I don't know what you actually want the code to do in this case.

How to write Big files into Blobstore using experimental API?

I have dilemma.. I'm uploading files both in scribd store and blobstore using tipfy as framework.
I have webform with action is not created by blobstore.create_upload_url (i'm just using url_for('myhandler')). I did it because if i'm using blobstore handler the POST response parsed and I cannot use normal python-scribd api to upload file into scribd store.
Now I have working scribd saver:
class UploadScribdHandler(RequestHandler, BlobstoreUploadMixin):
def post(self):
uploaded_file = self.request.files.get('upload_file')
fname = uploaded_file.filename.strip()
try:
self.post_to_scribd(uploaded_file, fname)
except Exception, e:
# ... get the exception message and do something with it
msg = e.message
# ...
# reset the stream to zero (beginning) so the file can be read again
uploaded_file.seek(0)
#removed try-except to see debug info in browser window
# Create the file
file_name = files.blobstore.create(_blobinfo_uploaded_filename=fname)
# Open the file and write to it
with files.open(file_name, 'a') as f:
f.write(uploaded_file.read())
# Finalize the file. Do this before attempting to read it.
files.finalize(file_name)
# Get the file's blob key
blob_key = files.blobstore.get_blob_key(file_name)
return Response('done')
def post_to_scribd(self, uploaded_file, fname):
errmsg =''
uploaded_file = self.request.files.get('upload_file')
fname = uploaded_file.filename.strip()
fext = fname[fname.rfind('.')+1:].lower()
if (fext not in ALLOWED_EXTENSION):
raise Exception('This file type does not allowed to be uploaded\n')
if SCRIBD_ENABLED:
doc_title = self.request.form.get('title')
doc_description = self.request.form.get('description')
doc_tags = self.request.form.get('tags')
try:
document = scribd.api_user.upload(uploaded_file, fname, access='private')
#while document.get_conversion_status() != 'DONE':
# time.sleep(2)
if not doc_title:
document.title = fname[:fname.rfind('.')]
else:
document.title = doc_title
if not doc_description:
document.description = 'This document was uploaded at ' + str(datetime.datetime.now()) +'\n'
else:
document.description = doc_description
document.tags = doc_tags
document.save()
except scribd.ResponseError, err:
raise Exception('Scribd failed: error code:%d, error message: %s\n' % (err.errno, err.strerror))
except scribd.NotReadyError, err:
raise Exception('Scribd failed: error code:%d, error message: %s\n' % (err.errno, err.strerror))
except:
raise Exception('something wrong exception')
As you can see it also saves file into blobstore.. But If i'm uploading big file (i.e. 5Mb) I'm receiving
RequestTooLargeError: The request to API call file.Append() was too large.
Request: docs.upload(access='private', doc_type='pdf', file=('PK\x03\x04\n\x00\x00\x00\x00\x00"\x01\x10=\x00\x00(...)', 'test.pdf'))
How can I fix it?
Thanks!
You need to make multiple, smaller calls to the file API, for instance like this:
with files.open(file_name, 'a') as f:
data = uploaded_file.read(65536)
while data:
f.write(data)
data = uploaded_file.read(65536)
Note that the payload size limit on regular requests to App Engine apps is 10MB; if you want to upload larger files, you'll need to use the regular blobstore upload mechanism.
finally i found solution.
Nick Johneson's answer occurred attribute error because uploaded_file is treated as string.
string didn't have read() method.
Cause string doesn't have method read(), i spliced file string and write it just like he wrote.
class UploadRankingHandler(webapp.RequestHandler):
def post(self):
fish_image_file = self.request.get('file')
file_name = files.blobstore.create(mime_type='image/png', _blobinfo_uploaded_filename="testfilename.png")
file_str_list = splitCount(fish_image_file,65520)
with files.open(file_name, 'a') as f:
for line in file_str_list:
f.write(line)
you can check about splitCount(). here
http://www.bdhwan.com/entry/gaewritebigfile

Categories

Resources