form.html:
<form action="p.py" method="post">
<input type="text" id="id_text" name="name_text" />
<input type="submit" id="id_submit" name="name_submit" />
</form>
p.py:
#!/usr/bin/python
#what to write here...
Both files are put in /var/www/ , now from http://example.com/form.html, if I click the submit button would I execute the p.py and how can I get the value of textbox?
It's apache/httpd webserver installed on computer.
1st, to make p.py run by apache, you need to check:
1, config apache site for a python script, you may choose: cgi/fastcgi
such as: ScriptAlias /cgi-bin/ /usr/local/xxxxxx/cgi-bin/
2, make sure your p.py file is runable, modify by chown/chmod
2nd, to get the value from a form, you need to understand cgi knowleges and get data from environment,
or much easier by using cgi module:
import cgi
form = cgi.FieldStorage()
v = form.getvalue('id_text','')
print """Content-type: text/html
<html>
<body> submit value:%s </body>
</html>""" % (v)
at last, I suggest:
put runable scripts to a separated dir, away from /var/www/
using a web framework for web develop. It's too deep to use cgi level technology in 2012.
Related
I have created html form with text box and button
enter ur search keyword
My requirement is to pass the text box value in to my test.py code, is there any way to do it.
Please suggest me how do it.
in the form action form action="", put the location of your cgi script and the value of the textbox will be passed to the cgi script.
eg.
<form name="search" action="/cgi-bin/test.py" method="get">
Search: <input type="text" name="searchbox">
<input type="submit" value="Submit">
</form>
in your test.py
import cgi
form = cgi.FieldStorage()
searchterm = form.getvalue('searchbox')
thus you will get the key word entered in search text box in searchterm variable in python.
I had the problem with getting the code in browser. Installed python and xampp.
I put the .py script in cgi-bin and I called it from an html page like that
<form name="input" action="../cgi-bin/name_of_script.py" method="get">
Put the html page in htdocs of xampp.
In the httd.conf find the line
AddHandler cgi-script .cgi .pl .asp
and change it to
AddHandler cgi-script .cgi .pl .asp .py
In the script add the version of the python you have
for example I added
#!C:\Python27\python.exe
because I have installed python27 in the above directory.
Also if you print something in python put this line on top of the script
print "Content-Type: text/html; charset=utf-8\n\n";
The above script of the searchbox it worked fine for me.
My operating system is Windows really torchered me, I searched and searched for the above solution.
I'm currently trying to create a simple login in page to my actual local webpage that I'm running with on a virtual machine with Ubuntu.
I created the LoginPage.html at the location /var/www/html.
The HTML file then calls the login.cgi file in the /usr/lib/cgi-bin/login.cgi.
I get an Internal Server Error. The logs basically only shows this:
"POST /cgi-bin/login.cgi HTTP/1.1" 500 799
"http://localhost/LoginPage.html" "Mozialla/5.0 (X11; Ubtuntu; Linux
x86_64; rv:84.0) Geck/201000101 Firefox/84.0
The HTML file seems to be working as intended, but when I press login and get redirected to the CGI file, I get the error on the CGI file. I have tried to remove everything the in the CGI file to leave only a couple of lines but still get the error.
My other project-files in the cgi-bin folder still work without an error.
<HTML>
<HEAD><TITLE>Login Page</TITLE></HEAD>
<BODY>
<CENTER>
<FORM method="POST" action="/cgi-bin/login.cgi">
<paragraph> Enter your login name: <input type="text" name="login">
<paragraph> Enter your password: <input type=password name="password">
<paragraph> <input type="submit" value="Connect">
</FORM>
</CENTER>
<HR>
</form>
</BODY>
</HTML>
#!/usr/bin/python3
import sys
import cgi
import os
import cgitb
sys.path.insert(0,'/usr/lib/project_name')
def header():
#print "Content-type: text/html\n"
print("<HEAD>")
print("<TITLE> title </TITLE>")
print("</HEAD>")
def Log():
print("<!DOCTYPE html>")
print("<HTML>")
print("<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">")
print(" <meta charset=\"utf-8\" />")
header()
print("BODY")
form = cgi.FieldStorage()
login = "login"
password = "test123"
if not (form):
header("Login Response")
print("<BODY>")
elsif (form.has_key("login") and form["login"].value == login and form.has_key("password") and form["password"].value == password):
header("Connected ...")
print("<BODY>")
print("<center><hr><H3>Welcome back,\" , form[\"login\"].value, \".</H3><hr></center>")
print("r\"\"\"<form><input type=\"hidden\" name=\"session\" value=\"%s\"></form>\"\"\" % (form[\"login\"].value)")
print("<H3>Click here to start browsing</H3>")
else:
header("No success!")
print("<BODY>")
print("<H3>Please go back and enter a valid login.</H3>")
def footer():
print("</BODY>")
print("</HTML>")
print("Content-type:text/html\r\n\r\n")
cgitb.enable()
Log()
footer()
Edit:
Here is the content of error.log after resolving the Internal Server Error:
[Tue Feb 02 08:40:41.199152 2021] [cgi:error] [pid 10292:tid
140490049578752] [client 127.0.0.1:38888] AH01215: (2)No such file or
directory: exec of '/usr/lib/cgi-bin/login.cgi' failed:
/usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html
[Tue Feb 02 08:40:41.199411 2021] [cgi:error] [pid 10292:tid
140490049578752] [client 127.0.0.1:38888] End of script output before
headers: login.cgi, referer: http://localhost/LoginPage.html
Correcting the setup:
No such file or directory: exec of '/usr/lib/cgi-bin/login.cgi' failed: /usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html
Make sure the CGI script and its parent directory have the right permissions:
chmod 755 /usr/lib/cgi-bin/ /usr/lib/cgi-bin/login.cgi
Also, it appears the CGI script may have windows line endings, so make sure you remove those as well, e.g. by running dos2unix login.cgi (see this post for more details).
Resolving the Internal Server Error:
First, make at least the following changes to correct your syntax (which is what's causing the Internal Server Error):
elsif should be elif
Your header function should take in an argument, i.e. def header(title)
Where you have form.has_key, change it to use in since has_key is now deprecated, e.g. "password" in form instead of form.has_key("password")
The corrected condition would look like this:
elif "login" in form and form["login"].value == login and "password" in form and form["password"].value == password:
As an aside, stick to HTML5, which is supported by all the latest browsers, and the center tag is now deprecated (its gone the way of the marquee tag). Use CSS instead.
Also, as a complete side note, these days, its uncommon to see ALL CAPS used for HTML tags. You have used that style in some places, but I suggest dropping it in favor of lowercase tag names.
Simplfying the HTML generation:
In addition to the above, I recommend using f-strings for string formatting and also multi-line strings to simplify the logic a bit.
Below are some examples of how you can enhance your code.
Your header function may look like this using f-strings and multi-line strings as suggested. The title argument is optional.
def header(title=""):
print(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
""")
Your footer function could look like this:
def footer():
print("""
</body>
</html>
""")
Finally, your HTML form could look like this, using text-align: center; for the centering:
print(f"""
<hr>
<h3 style="text-align: center;">Welcome back { form["login"].value }</h3>
<hr>
<form>
<input type="hidden" name="session" value="{ form["login"].value }">
</form>
<h3>
Click here to start browsing
</h3>
""")
Beautifying the HTML:
To beautify the HTML further, you can import textwrap and then use textwrap.dedent() to remove the common leading spaces from the HTML (due to the indentation in Python), e.g.
print(textwrap.dedent(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
"""))
This gives two advantages:
It removes the unnecessary leading spaces before sending it over the network -- so you send less data, saving bandwidth
The HTML source is prettier when you inspect it using a client browser -- useful for debugging
Alternatively, use HTML templating:
A further enhancement is to make use of a HTML templating framework, such as Jinja2. This will allow you to store the HTML into files and then render the HTML files by passing variables.
Then, your Python code would become a lot simpler. You would just render the template and pass the variables you want. For example, for you header, it could be like this:
template = env.get_template('header.html')
print(template.render(title='Connected ...'))
You will need to set up the Environment like this first:
from jinja2 import Environment
env = Environment(
loader=PackageLoader('package', 'templates')
autoescape=select_autoescape(['html'])
)
And place your header.html file in a directory called templates.
You may also want to read about the seperation of concerns principle and the MVC architecture. Using templates like this is just one step closer to achieving MVC.
Final point on security:
It looks like you are using a HTML hidden field to store the username, and treating that as a session token. This is highly insecure and won't scale. Though, it may be sufficient for your purposes. A simple way to improve on it is to store it as a cookie using the Set-cookie header, and make it HttpOnly, e.g.
Set-cookie: session=value; HttpOnly
where value could be some unique token (e.g. a uuid).
This is much better than your current approach.
But, even better yet, you could implement security using a library like PyJWT instead.
I have an Apache web server. I have an html file and a Python script located at var/www/myfolder. I am submitting a form through the html file which is handled by my Python script (when the submit button is clicked). But once handling the form, my Python script executes an external command. (see the following code)
webpage.html
<!DOCTYPE html>
<html>
<head>
<title>Webform</title>
</head>
<body>
<h3>Webform</h3>
<form action="myscript.py" method="POST">
<p>Name: <input type="text" name="name"></p>
<input type="submit" value="Submit">
</form>
</body>
</html>
myscript.py
#!/usr/bin/python -W
import cgi, cgitb
import sys
import os
# Get data from fields
form = cgi.FieldStorage()
name = form.getvalue('name')
print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello Word - First CGI Program</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! This is my first CGI program</h2></br></br>'
print '<p>Name: %s</p>' % (name)
print '</body>'
print '</html>'
os.system("./other_script.py") # gives me an error with permission
On my server I am user007 but I know that when I click submit on the html file, the Python script is executed as apache2 user. The problem is I don't know the password for this user (can't us sudo). Are the two ideas possible:
1) change from apache2 to user007 when trying to execute other_script.py from myscript.py
2) I know that you can change users using suEXEC but I have no idea how to use it.
Any suggestions?
I should let you know that locally both the python scripts are executing fine.
Edit 1:
I get this message before the error occurs: WARNING: HOME is not set, using root: /
I've been stumbling along with the same problem for almost a year now. I always find a way to work around it, but I'm tired of finding work arounds.
What I need is to create a button on a Web Page (preferable HTML, not PHP or ASP) that runs a python script on the server. I'd also like the ability to have this button send information from a form to the script.
I need to do this on a local host and through a web service hosted on the Amazon Cloud. I won't be able to install anything extra on the Amazon Cloud service, such as PHP or CGI.
I'd really like an easy solution, I'm an expert with python and I can write webpages that whistle, but I just can't find a simple solution to this problem.
My ideal solution would be something like the mail to tag:
Send Mail
Except:
Run Script
Now I highly doubt a solution like that exists, but well I can dream right.
The script I am trying to run:
Returns a Unique ID from the user
Sends the ID to a GIS program that creates a map based on the ID (the ID selects the area of the map)
The map is then exported to a PNG, wrote into an HTML document and then displayed for the user in a new tab.
EDIT ---------------------------
Thanks to #Ketouem answer I was able to find a great solution to my issue. I'll post some of the code here so that others can benefit. Make sure you download the Bottle Module for python, its great.
# 01 - Import System Modules
from bottle import get, post, request, Bottle, run, template
# 02 - Script Variables
app = Bottle()
# 03 - Build Temporary Webpage
#app.route('/SLR')
def login_form():
return '''<form method="POST" action="/SLR">
Parcel Fabric ID: <input name="UID" type="text" /><br />
Save Location: <input name="SaveLocation" type="text" value="D:/Python27/BottleTest/SLR_TestOutputs"/><br />
Air Photo On: <input name="AirPhoto" type="checkbox"/><br />
Open on Completion: <input name="Open" type="checkbox"/><br />
Scale: <input name="Scale" type="text" value="10000"/><br />
<input type="submit" />
</form>'''
# 04 - Return to GIS App
#app.route('/SLR', method='POST')
def PHPH_SLR_Script():
# I won't bother adding the GIS Section of the code, but at this point it send the variables to a program that makes a map. This map then saves as an XML and opens up in a new tab.
# 04 - Create and Run Page
run(app, host='localhost', port=8080)
You could use Bottle : http://bottlepy.org/docs/dev/index.html which is a light web framework
I have written an html form and am trying to incorporate a python cgi script with it. I have already configured my apache server to execute cgi scripts from the cgi-bin directory. Here's the html form:
<html>
<body>
<form name="input" action="c:/xampp/cgi-bin/test2.py" method="post">
<input type="text" name="qry" />
<input type="submit" value="GO!" />
</form>
</body>
</html>
And here's the test2.py cgi script:
#!c:/Python27/python.exe -u
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
qry = form["qry"].value
print "Content-Type: text/html"
print
print "<html"
print "<body>"
print qry
print "</body>"
print "</html>"
The html page is located in my htdocs folder and the cgi script is in the cgi-bin directory. However, when I enter something into the form and submit, firefox returns an error message saying: "Firefox doesn't know how to open this address, because the protocol (c) isn't associated with any program". Why is this error occurring? Does it have something to do with my path to the cgi script in my html page? Thanks in advance!
You are correct: it has something to do with the path to the CGI script on the HTML page. The form's action attribute should refer to the path where the CGI script is getting interpreted on the server, e.g., /cgi-bin/test2.py.
Since you made this mistake, I'm assuming you are new to web development. Consider using mod_wsgi and a framework like Django instead of CGI, especially if you expect a lot of traffic or you are making a web application and not just handling a single form.