Reading a file uploaded via CGI in Python - python

I am having trouble analyzing a file that is uploaded to my server. Ideally, what would happen is that the user would upload a .csv and I would run some numeric integration (hence the import numpy as np) from data in the file and return the result. To test the cgi part before I did any analysis, I made the python script below. My problem is that message always appears blank, so I get a blank html page displayed in browser at the end.
Clearly I am not reading the file correctly (which means I can not analyze it), but I have n o idea what I am doing wrong. My own searches indicate that what I have below should work.
#!/usr/bin/python
#---------------------------------------------
#=============================================
#---------------------------------------------
#imports
#import csv
#import time as tm
#import numpy as np
#import os
import cgi, cgitb
cgitb.enable()
form = cgi.FieldStorage()
#The variables
#httpopen=""
#httpclose=""
message="meow"
#get the fileitem
fileitem=form['userfile']
if fileitem.file:
#yay...we got a file
message=fileitem.file.readline()
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
And here is the html form that gives the upload:
<html>
<body>
<form enctype="multipart/form-data"
action="capacity_rewrite.py" method="post">
<p>File: <input type="file" name="userfile" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
Thanks,

You're only reading one line from the uploaded file. Perhaps that first line is a blank line? Try fileitem.file.read() instead, which will read the entire file into a string. Don't do that for large files as you may run out of memory, but it should help in understanding your test.

Related

How do I receive an excel file as input using Flask and read it using openpyxl?

I've created a python script that loads an excel file up from my computer and, after working with the information inside it using openpyxl, saves a new excel file. The script works on my computer. For longevity purposes, I want to make the script into a website, using pythonanywhere or something similar to it (incorporating flask seemed like the best way to convert my script into a website). However, I am having trouble finding a way to accept a file from the user, as I have very little experience using flask. Here's the code I currently have that creates a "choose file" button and a "process file" button:
app = Flask(__name__)
app.config["DEBUG"] = True
#app.route("/", methods=["GET", "POST"])
def file_summer_page():
if request.method == ("POST"):
input_file = request.files["input_file"]
wb_master = load_workbook(input_file)
output_data = main(wb_master)
response = make_response(output_data)
response.headers["Content-Disposition"] = "attachment; filename=result.csv"
return response
return '''
<html>
<body>
<p>Load up the automated eval that MS Forms gives you:</p>
<form method="post" action="." enctype="multipart/form-data">
<p><input type="file" name="input_file" /></p>
<p><input type="submit" value="Process the file" /></p>
</form>
</body>
</html>
'''
Bear with me. Again, I haven't used Flask much, but this is my idea so far. Main(wb_master) essentially calls the script I made, so that it could hopefully run. At the moment, this returns the following error: "AttributeError: 'SpooledTemporaryFile' object has no attribute 'seekable'." In this case, I don't really know what it means, but I assume it is due to the fact that I am not reading the file correctly. Any help would be greatly appreciated!

How to get utf-8 from forms in Bottle?

I am trying to use Bottle.py to get input information from users in a web page.
Everything works fine except when I have latin characters (accents mostly). I have try using utf-8 and latin-1 coding on the first two lines of the code, but it won't work.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import bottle
#bottle.post('/newpost')
def post_newpost():
subject = bottle.request.forms.get("subject")
body = bottle.request.forms.get("body")
tags = bottle.request.forms.get("tags")
and the html code from the page is:
<html>
<head>
<meta charset="utf-8" />
<title>New Posts</title>
</head>
<body>
<form action="/newpost" method="POST">
<h2>Post title</h2>
<input type="text" name="subject" size="120" value="{{subject}}" ><br>
<h2>Post<h2>
<textarea name="body" cols="120" rows="20">{{body}}</textarea><br>
<h2>Tags</h2>
<input type="text" name="tags" size="120" value="{{tags}}"><br>
<p>
<input type="submit" value="Submit">
</body>
</html>
I read in Bottle page that:
In Python 3 all strings are unicode, but HTTP is a byte-based wire
protocol. The server has to decode the byte strings somehow before
they are passed to the application. To be on the safe side, WSGI
suggests ISO-8859-1 (aka latin1), a reversible single-byte codec that
can be re-encoded with a different encoding later. Bottle does that
for FormsDict.getunicode() and attribute access, but not for the
dict-access methods. These return the unchanged values as provided by
the server implementation, which is probably not what you want.
request.query['city']
'Göttingen' # An utf8 string provisionally decoded as ISO-8859-1 by the server
request.query.city
'Göttingen' # The same string correctly re-encoded as utf8 by bottle
If you need the whole dictionary with correctly decoded values (e.g. for WTForms), you can call FormsDict.decode() to get a re-encoded copy.
After reading that I tried using that function but don't know how.
Right now Bottle form returns strings, so I can not use encode('utf-8') or decode('utf-8').
Please help me!
Thanks!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import bottle
#bottle.post('/newpost')
def post_newpost():
subject = bottle.request.forms.subject
body = bottle.request.forms.body
tags = bottle.request.forms.tags
That will do it.... Thanks!

how to send response to html using cgi python script

I am trying to design and implement a basic calculator in HTML and Python(using CGI). Below given is a static HTML web page and it is being redirected to a python script (calci.py) where, I am able to calculate the sum but unable to append the resultant to the 'output' textbox.
calculator.html
<html>
<head>
<title>Calculator</title>
</head>
<body>
<form action="python_scripts/calci.py" method="post">
Input 1 : <input type="text" name="input1"/><br>
Input 2 : <input type="text" name="input2"/><br>
<input type="submit" value="+" title="add" /><br>
output : <input type="text" name="output"/><br>
</form>
</body>
</html>
calci.py
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
output = str(int(input1)+int(input2))
#how to return the response to the html
#and append it to the textbox
Thanks
This is not the way Web applications work - not hat simply, at least.
If you want to rely only on the browser, and plain HTML for your application, each request has to send the whole html page as a string. You have to use Python's string formatting capabilities to put the resulting number in the correct place in the HTML form.
This way of working is typical of "Web 1.0" applications (as opposed to the "Web 2.0" term used about ten years ago).
Modern web applications use logic that runs on the client side, in Javascript code, to make an HTTP request to retrieve only the needed data - and them, this client-side logic would place your result in the proper place in the page, without reloading the page. This is what isgenerally known as "ajax". It is not that complex, but the html + javascript side of the application become much more complex.
I think one should really understand the "Web 1.0" way before doing it the "Ajax way". in your case, let's suppose your HTML containing the calculator form is in a file called "calc.html". Inside it, where the result should lie, put a markup that can be understood by Python's built-in native string formatting methods, like {result} -
<html>
<body>
...
calculator body
...
Answer: <input type="text" readonly="true" value={result} />
</body>
</html>
And rewrite your code like:
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
result = int(input1)+int(input2)
html = open("calc.html".read())
header = "Content-Type: text/html; charset=UTF-8\n\n"
output = header + html.format(result=result)
print (output)
The CGI way is outdated, but is nice for learning: it relies on your whole program being run, and whatever it prints to the standard output to be redirected to the HTTP request as a response. That includes the HTTP Headers, which are included, in a minimal form, above.
(I will leave the complete implementation of a way for the raw '{result}' string not to show up in the inital calculator form as an exercise from where you are 0- the path is to get the initial calculator html template through a CGI script as well, instead of statically, (maybe the same) as well - and just populate "result" with "0" or an empty string)
you can transfer response with the help of java script.
use under print("window.location=url")

Python / CGI - Upload file attempt returns an empty page

I really searched about 50 related pages but never seen a problem similar to my problem. When I press the submit button, it calls the script but the script returns an empty page and I see no file was uploaded. There is no typing error in my codes, I checked it several times and I really need this code running for my project. What might be the problem? I am running apache under ubuntu and my codes are:
html code:
<html><body>
<form enctype="multipart/form-data" action="save_file.py" method="post">
<p>File: <input type="file" name="file"></p>
<p><input type="submit" value="Upload"></p>
</form>
</body></html>
python code:
#!/usr/bin/env python
import cgi, os
import cgitb; cgitb.enable()
try: #windows needs stdio set for binary mode
import msvcrt
msvcrt.setmode (0, os.O_BINARY)
msvcrt.setmode (1, os.O_BINARY)
except ImportError:
pass
form = cgi.FieldStorage()
#nested FieldStorage instance holds the file
fileitem = form['file']
#if file is uploaded
if fileitem.filename:
#strip leading path from filename to avoid directory based attacks
fn = os.path.basename(fileitem.filename)
open('/files' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
I just tested your script, with a few small corrections to the paths to make it work for me locally. With the paths set correctly, and permissions set properly, this code does work fine.
Here are the things to make sure of:
In your html file's form properties, make sure you are pointing to the python script that lives in a cgi-bin: action="/cgi-bin/save_file.py". For me, I have a cgi-bin at the root of my web server, and I placed the python script there. It will not work if you are running the script from a standard document location on the web server
Make sure your save_file.py has executable permissions: chmod 755 save_file.py
In your save_file.py, ensure that you are building a valid path to open the file for saving. I made mine absolute just for testing purposes, but something like this: open(os.path.join('/path/to/upload/files', fn)
With those points set correctly, you should not have any problems.

Need to get the uploaded file to my local PC

I have created a test form which will ask users to enter a name and upload the image file:
<html lang="en">
<head>
<title>Testing image upload</title>
</head>
<body>
<form action="/services/upload" method="POST" enctype="multipart/form-data">
File Description: <input name='fdesc' type='text'><br>
File name: <input type="file" name="fname"><br>
<div><input type="submit"></div>
</form>
</body>
</html>
i need to get the file uploaded by the user and store it on my local PC. can this be done in python ? please let me know.
mod_python includes the FieldStorage class which allows you access to uploaded form data. In order to use it, you'd put something like the following in your Python script:
req.form = FieldStorage(req)
description = req.form['fdesc']
Since fdesc is a text input, description will be a string (more precisely, a StringField, which you can treat as a string).
file_field = req.form['fname']
Since fname is a file input, file_field will not be a string (or StringField), but rather a Field object which allows you access to the file data. The attribute file_field.file is a file-like object which you can use to read the file's contents, for example like so:
for line in file_field.file:
# process the line
You could use this to copy the file's data somewhere of your choosing, for example.
file_field.filename is the name of the file as provided by the client. Other useful attributes are listed in the documentation I linked to.
Maybie the minimal http cgi upload recipe and it's comments are helpful for you.
Hey David i got it working, i did it this way:
filename = request.FILES['fname']
destination = open('%s/%s'%(/tmp/,fileName), 'wb+')
for chunk in filename.chunks():
destination.write(chunk)
destination.close()
file = open('%s/%s'%(/tmp/,fileName),"rb").read()
Thanks for the help guys.

Categories