I am trying to run a standard python os.system call from a cgi python script.
This is part of a tutorial so the script is quite simple. I am trying to take a picture with the Raspberry Pi camera and display it in a webpage.
import os, sys
os.system('raspistill -o /var/www/images/image.jpg')
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>'
print '<img src="/var/www/images/image.jpg"/>'
print '</body>'
print '</html>'
The error I get when running the system command (opening in a browser) is:
* failed to open vchiq instance"
I have seen another question on this and it said something about the http deamon running as the wrong user, but I am not sure what that meant.
The scripts runs fine when I am running it as the standard user.
Most web servers run with a user for the webserver. Apache2 runs as www-data, for instance.
All files in the computer have ownership and permission data for them that would allow or disallow certain operations from different users - for instance only the superuser (root) can run the poweroff application to turn off the computer.
What you should do is locate the executable you're trying to run which raspistill. This will return the location of the executable file. Next you should check the file permissions using ls -l `which raspistill` and see the owner data and file permissions which are displayed as -rwxr-xr-- (This is a common permission set, yours might vary). The 1st 3 represent Read-Write-eXecute permissions for the file owner, the next 3 chars represent only Read and eXecute permissions for the user group and the last 3 chars represent only Read permissions for the "other" users.
If the owner of the file is not www-data you could do several things such as change the ownership information for the file using chown <user> <file> which I don't recommend or adding execution privileges to the "other" user set with chmod o+x `which raspistill`.
If the problem is indeed with the permissions - this should solve your problem.
Additional information:
http://www.computerhope.com/unix/uchmod.htm
http://www.ss64.com/bash/chmod.html
I fixed it.
The web server had access to the raspistill command, but that command used a video device that it did not have access to. I added the www-data user to the video and the audio group so I could both play audio and take pictures. I also had to change some groups for some folders in my web-directory.
The last thing I had to fix was that the os.system() call returned something and that gave the browser some problems with displaying the webpage. It only displayed text. I now use the subprocess module and the initial code seems to work. My simple test code is here:
import os, sys
import subprocess
#output = subprocess.check_output("raspistill -o /var/www/images/image.jpg", shell=True)
#os.system('raspistill -v -o /var/www/images/image.jpg')
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
output = ""
output2 = ""
# Get data from fields
if form.getvalue('speak_en'):
output = subprocess.check_output("espeak \"%s\"" % (form.getvalue('speak')), shell=True)
if form.getvalue('picture'):
output2 = subprocess.check_output("raspistill -o /var/www/images/image.jpg", shell=True)
print """\
Content-type:text/html\n
<html>
<head>
<title>Hello Word - First CGI Program</title>
</head>
<body>
<h2>Select photo or speak</h2>
<form action=\"/cgi-bin/hello.py\" method=\"post\">
<input type=\"checkbox\" name=\"speak_en\" value=\"on\" />
Speak: <input type=\"text\" name=\"speak\"><br />
Take picture:
<input type=\"checkbox\" name=\"picture\" value=\"on\" />
<br />
<input type=\"submit\" value=\"Submit\" />
</form>
<img src=\"../images/image.jpg\" width=640 height=480>
<p>Speak output: %s</p>
<p>Picture output: %s</p>
</body>
</html>
""" % (output, output2)
Related
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: /
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.
So I'm trying to modify some HTML to have a button that initiates a python script that acts on a few files in ones own system.
more specifically, i have a python script that reads through snort logs and produces a link to a new website (really, an IP address that takes parameters for a packet-capture stream search)
I'm trying to implement this script as a button on a website.
-note: it's ok if whoever is clicking on the button(s) needs to have the script.py on their own machine
I've tried to do my homework on the subject, but there seem to be infinite options - most of which aren't agreed upon by any 2 parties.
Do i NEED a framework? can i not just call my python script from its directory using some < script / >'s or something in my HTML code?
Short answer: you can't.
You can't access files on the user's machine, and even less execute them, from the browser. Imagine how much of a security hole that would be.
However, you could implement your own simple web browser (that displays a single page for example) in many GUI toolkits (Qt or wx have web views or similar). Or, you would need to develop (or find) a plugin/addon to the browser you are using, and communicate with that. It will depend on each browser, etc. I have no idea if this is feasible. Or, the user will download a file which he will choose to run instead of save, that will execute your script.
Actually, I just saw this and this which is basically a plugin that you install (based on IronPython and Silverlight), I'm not sure you can execute scripts that are on the user's system though. It can execute code embedded in the page.
Alternative Solution to the OPs question:
Synopsis of solution:
Send user input via HTML Form with 'GET'
Process values from the url encoded values 'GET' sent to the shell script
Shell script parses values and saves them passing the arguments to the Python script while calling it to run.
Javascript and php work nicely with this setup and allows for mysql, etc. from there.
Using 'GET' we send the user's input from client side to server side using a shell script to process our data.
Example Index.php
<!DOCTYPE html>
<html>
<head>
<title>Google Email Search</title>
</head>
<body>
<h1>Script Options</h1>
<form action="/cgi-bin/call.sh" method="get">
<TABLE BORDER="1">
<TR>
<TD>Keyword:</TD>
<TD><input type="text" name="query" value="Query"></TD>
</TR>
<TR>
<TD># of Pages:</TD>
<TD><input type="text" name="pages" value="1"></TD>
</TR>
<TR>
<TD>Output File Name:</TD>
<TD><input type="text" name="output_name" value="results"></TD>
</TR>
<TR>
<TD>E-mail Address:</TD>
<TD><input type="text" name="email_address" value="example#gmail.com">
</TD>
</TR>
<TR>
<TD><input type="submit" value="Submit"></TD>
</TR>
</TABLE>
</form>
</body>
</html>
Example shell script to call the python script which would be located in your cgi-bin or other designated 'executable' allowed directory.
#!/bin/bash
# Runs the cgi-script, using the shell, using 'get' results from the index html form we parse it to the options in the python script.
echo "Content-type: text/html"
echo ""
echo '<html>'
echo '<head>'
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
echo '<title></title>'
echo '</head>'
echo '<body>'
query=`echo "$QUERY_STRING" | sed -n 's/^.*query=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`
pages=`echo "$QUERY_STRING" | sed -n 's/^.*pages=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`
output_name=`echo "$QUERY_STRING" | sed -n 's/^.*output_name=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`
email_address=`echo "$QUERY_STRING" | sed -n 's/^.*email_address=\([^&]*\).*$/\1/p' | sed "s/%20/ /g"`
echo '<h1>'
echo 'Running...'
echo '</h1>'
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
cd "$DIR"
python main.py -query $query -pages $pages -o $output_name
echo ''
echo '</body>'
echo '</html>'
Example Python script.
called from the shell script:
#!/usr/bin/env python
from xgoogle.search import GoogleSearch
import urllib2, re, csv, os
import argparse
class ScrapeProcess(object):
emails = [] # for duplication prevention
def __init__(self, filename):
self.filename = filename
self.csvfile = open(filename, 'wb+')
self.csvwriter = csv.writer(self.csvfile)
def go(self, query, pages):
search = GoogleSearch(query)
search.results_per_page = 10
for i in range(pages):
search.page = i
results = search.get_results()
for page in results:
self.scrape(page)
def scrape(self, page):
try:
request = urllib2.Request(page.url.encode("utf8"))
html = urllib2.urlopen(request).read()
except Exception, e:
return
emails = re.findall(r'([A-Za-z0-9\.\+_-]+#[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html)
for email in emails:
if email not in self.emails: # if not a duplicate
self.csvwriter.writerow([page.title.encode('utf8'), page.url.encode("utf8"), email])
self.emails.append(email)
parser = argparse.ArgumentParser(description='Scrape Google results for emails')
parser.add_argument('-query', type=str, default='test', help='a query to use for the Google search')
parser.add_argument('-pages', type=int, default=10, help='number of Google results pages to scrape')
parser.add_argument('-o', type=str, default='emails.csv', help='output filename')
args = parser.parse_args()
args.o = args.o+'.csv' if '.csv' not in args.o else args.o # make sure filename has .csv extension
s = ScrapeProcess(args.o)
s.go(args.query, args.pages)
Full working example located here:
https://github.com/mhenes/Google-EmailScraper
Disclaimer this is my git- using a forked project to show this functionality.
IronPython may have been the solution you were looking for:
http://ironpython.net/
With the tutorials and code provided in the below link, you should be able to create html elements that react to events such as an html "button" like you mentioned.
I've been playing with IronPython and have had success with internal and external calls to scripts. The tutorial below most likely contains any other questions you may have.
helloworld.html -
IronPython alert example, internal python scripting in document.
To develop a Python application in the browser, you just need your favorite text editor; so open it up, create a HTML file, reference dlr.js, and then you can use script-tags for running Python code:
<html>
<head>
<script src="http://gestalt.ironpython.net/dlr-latest.js"
type="text/javascript"></script>
</head>
<body>
<script type="text/python">
window.Alert("Hello from Python")
</script>
</body>
</html>
repl.py
to do this in a REPL window, so let's turn one on in the browser; just place the following script-tag in the page:
from Microsoft.Scripting.Silverlight import Repl
if 'document' not in globals():
import System
document = System.Windows.Browser.HtmlPage.Document
if 'window' not in globals():
import System
window = System.Windows.Browser.HtmlPage.Window
class PythonRepl(object):
__ironpython__ = 'silverlightDlrRepl1'
__minimize__ = 'silverlightDlrWindowLink'
__container__ = 'silverlightDlrWindowContainer'
def __init__(self):
self.repl = Repl.Show('python')
def hide_all_panels(self):
window.Eval("sdlrw.hideAllPanels(document.getElementById(\"%s\"))" % self.__minimize__)
def show_panel(self, id):
window.Eval("sdlrw.showPanel(\"%s\")" % id)
def show_ironpython(self):
self.show_panel(self.__ironpython__)
def remove(self):
document.Body.RemoveChild(document.silverlightDlrWindowContainer)
def show():
prepl = PythonRepl()
repl = prepl.repl
import sys
sys.stdout = repl.OutputBuffer
sys.stderr = repl.OutputBuffer
return prepl
if document.QueryString.ContainsKey('console'):
prepl = show()
if document.QueryString['console'] == 'hide':
prepl.hide_all_panels()
else:
prepl.show_ironpython()
dom.py
IronPython example: for adding a DOM element and changing it's HTML content to "Ouch!" when clicked:
dir(document)
div = document.CreateElement("div")
div.innerHTML = "Hello from Python!"
document.Body.AppendChild(div)
div.id = "message"
div.SetStyleAttribute("font-size", "24px")
def say_ouch(o, e):
o.innerHTML = "Ouch!"
document.message.events.onclick += say_ouch
Caveat to note: IronPython requires SilverLight and therefore it will only work with FireFox or Safari.
Excellent tutorial related to your question:
http://jimmy.schementi.com/2010/03/pycon-2010-python-in-browser.html
I want user to enter a sentence then I break up that sentence into a list. I got the html page down but i have trouble passing that sentence to python.
How do I properly send the user input to be processed by python and output it to a new page?
There are many Python web frameworks. For example, to break up a sentence using bottle:
break-sentence.py:
#!/usr/bin/env python
from bottle import request, route, run, view
#route('/', method=['GET', 'POST'])
#view('form_template')
def index():
return dict(parts=request.forms.sentence.split(), # split on whitespace
show_form=request.method=='GET') # show form for get requests
run(host='localhost', port=8080)
And the template file form_template.tpl that is used both to show the form and the sentence parts after processing in Python (see index() function above):
<!DOCTYPE html>
<title>Break up sentence</title>
%if show_form:
<form action="/" method="post">
<label for="sentence">Input a sentence to break up</label>
<input type="text" name="sentence" />
</form>
%else:
Sentence parts:<ol>
%for part in parts:
<li> {{ part }}
%end
</ol>
%end
request.forms.sentence is used in Python to access user input from <input name="sentence"/> field.
To try it you could just download bottle.py and run:
$ python break-sentence.py
Bottle server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
Now you can visit http://localhost:8080/.
Have you tried Google? This page sums up the possibilities, and is one of the first results when googling 'python html'.
As far as I know, the two easiest options for your problem are the following.
1) CGI scripting. You write a python script and configure it as a CGI-script (in case of most HTTP-servers by putting it in the cgi-bin/ folder). Next, you point to this file as the action-attribute of the form-tag in your HTML-file. The python-script will have access to all post-variables (and more), thus being able to process the input and write it as a HTML-file. Have a look at this page for a more extensive description. Googling for tutorials will give you easier step-by-step guides, such as this one.
2) Use Django. This is rather suited for larger projects, but giving it a try on this level may provide you certain insights, and wetting your appetite for future work ;)
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.