# Introduction # # There is no standard cgi/web framework in python, # this is reason for ranting now and then. # # See `PyWebOff <http://pyre.third-bit.com/pyweb/index.html>`__ # which compares CherryPy, Quixote, Twisted, WebWare and Zope # Karrigell and print stantements. # # Then there is Nevow and Standalone ZPT. |
# Partial implementation of PLEAC Python section 19.1 # Written by Seo Sanghyeon # Standard CGI module is where PERL shines. Python # module, cgi, is nothing but a form parser. So it is # not really fair to compare these two. But I hesitate # to introduce any non-standard module. After all, # which one should I choose? # I would stick to simple print statements. I believe # the following is close to how these tasks are usually # done in Python. #----------------------------- #!/usr/bin/env python # hiweb - using FieldStorage class to get at form data import cgi form = cgi.FieldStorage() # get a value from the form value = form.getvalue("PARAM_NAME") # print a standard header print "Content-Type: text/html" print # print a document print "<P>You typed: <TT>%s</TT></P>" % ( cgi.escape(value), ) #----------------------------- import cgi form = cgi.FieldStorage() who = form.getvalue("Name") phone = form.getvalue("Number") picks = form.getvalue("Choices") # if you want to assure `picks' to be a list picks = form.getlist("Choices") #----------------------------- # Not Implemented # To implement -EXPIRES => '+3d', I need to study about import cgi import datetime time_format = "%a, %d %b %Y %H:%M:%S %Z" print "Expires: %s" % ( (datetime.datetime.now() + datetime.timedelta(+3)).strftime(time_format) ) print "Date: %s" % (datetime.datetime.now().strftime(time_format)) print "Content-Type: text/plain; charset=ISO-8859-1" #----------------------------- # NOTES # CGI::param() is a multi-purpose function. Here I want to # note which Python functions correspond to it. # PERL version 5.6.1, CGI.pm version 2.80. # Python version 2.2.3. cgi.py CVS revision 1.68. # Assume that `form' is the FieldStorage instance. # param() with zero argument returns parameter names as # a list. It is `form.keys()' in Python, following Python's # usual mapping interface. # param() with one argument returns the value of the named # parameter. It is `form.getvalue()', but there are some # twists: # 1) A single value is passed. # No problem. # 2) Multiple values are passed. # PERL: in LIST context, you get a list. in SCALAR context, # you get the first value from the list. # Python: `form.getvalue()' returns a list if multiple # values are passed, a raw value if a single value # is passed. With `form.getlist()', you always # get a list. (When a single value is passed, you # get a list with one element.) With `form.getfirst()', # you always get a value. (When multiple values are # passed, you get the first one.) # 3) Parameter name is given, but no value is passed. # PERL: returns an empty string, not undef. POD says this # feature is new in 2.63, and was introduced to avoid # "undefined value" warnings when running with the # -w switch. # Python: tricky. If you want black values to be retained, # you should pass a nonzero `keep_blank_values' keyword # argument. Default is not to retain blanks. In case # values are not retained, see below. # 4) Even parameter name is never mentioned. # PERL: returns undef. # Python: returns None, or whatever you passed as the second # argument, or `default` keyword argument. This is # consistent with `get()' method of the Python mapping # interface. # param() with more than one argument modifies the already # set form data. This functionality is not available in Python # cgi module. |
# enable() from 'cgitb' module, by default, redirects traceback # to the browser. It is defined as 'enable(display=True, logdir=None, # context=5)'. # equivalent to importing CGI::Carp::fatalsToBrowser. import cgitb cgitb.enable() # to suppress browser output, you should explicitly say so. import cgitb cgitb.enable(display=False) # equivalent to call CGI::Carp::carpout with temporary files. import cgitb cgitb.enable(logdir="/var/local/cgi-logs/") # Python exception, traceback facilities are much richer than PERL's # die and its friends. You can use your custom exception formatter # by replacing sys.excepthook. (equivalent to CGI::Carp::set_message.) # Default formatter is available as traceback.print_exc() in pure # Python. In fact, what cgitb.enable() does is replacing excepthook # to cgitb.handler(), which knows how to format exceptions to HTML. # If this is not enough, (usually this is enough!) Python 2.3 comes # with a new standard module called 'logging', which is complex, but # very flexible and entirely customizable. |
# # download the following standalone program #!/usr/bin/python # webwhoami - show web users id import getpass print "Content-Type: text/plain\n" print "Running as %s\n" % getpass.getuser() # STDOUT/ERR flushing # # In contrast to what the perl cookbook says, modpython.org tells # STDERR is buffered too. |
# @@INCOMPLETE@@ # @@INCOMPLETE@@ |
# use mod_python in the Apache web server. # Load the module in httpd.conf or apache.conf LoadModule python_module libexec/mod_python.so <Directory /some/directory/htdocs/test> AddHandler mod_python .py PythonHandler mptest PythonDebug On </Directory> # test.py file in /some/directory/htdocs/test from mod_python import apache def handler(req): req.write("Hello World!") return apache.OK |
import os os.system("command %s %s" % (input, " ".join(files))) # UNSAFE # python doc lib cgi-security it says # # To be on the safe side, if you must pass a string gotten from a form to a shell # command, you should make sure the string contains only alphanumeric characters, dashes, # underscores, and periods. import re cmd = "command %s %s" % (input, " ".join(files)) if re.search(r"[^a-zA-Z0-9._\-]", cmd): print "rejected" sys.exit(1) os.system(cmd) trans = string.maketrans(string.ascii_letters+string.digits+"-_.", # @@INCOMPLETE@@ # @@INCOMPLETE@@ |
#----------------------------- # This uses nevow's (http://nevow.com) stan; there's no standard # way to generate HTML, though there are many implementations of # this basic idea. from nevow import tags as T print T.ol[T.li['red'], T.li['blue'], T.li['green']] # <ol><li>red</li><li>blue</li><li>green</li></ol> names = 'Larry Moe Curly'.split() print T.ul[ [T.li(type="disc")[name] for name in names] ] # <ul><li type="disc">Larry</li><li type="disc">Moe</li> # <li type="disc">Curly</li></ul> #----------------------------- print T.li["alpha"] # <li>alpha</li> print T.li['alpha'], T.li['omega'] # <li>alpha</li> <li>omega</li> #----------------------------- states = { "Wisconsin": [ "Superior", "Lake Geneva", "Madison" ], "Colorado": [ "Denver", "Fort Collins", "Boulder" ], "Texas": [ "Plano", "Austin", "Fort Stockton" ], "California": [ "Sebastopol", "Santa Rosa", "Berkeley" ], } print "<TABLE> <CAPTION>Cities I Have Known</CAPTION>"; print T.tr[T.th('State'), T.th('Cities')] for k in sorted(states.keys()): print T.tr[ [T.th(k)] + [T.td(city) for city in sorted(states[k])] ] print "</TABLE>"; #----------------------------- # <TABLE> <CAPTION>Cities I Have Known</CAPTION> # # <TR><TH>State</TH> <TH>Cities</TH></TR> # # <TR><TH>California</TH> <TD>Berkeley</TD> <TD>Santa Rosa</TD> # # <TD>Sebastopol</TD> </TR> # # <TR><TH>Colorado</TH> <TD>Boulder</TD> <TD>Denver</TD> # # <TD>Fort Collins</TD> </TR> # # <TR><TH>Texas</TH> <TD>Austin</TD> <TD>Fort Stockton</TD> # # <TD>Plano</TD></TR> # # <TR><TH>Wisconsin</TH> <TD>Lake Geneva</TD> <TD>Madison</TD> # # <TD>Superior</TD></TR> # # </TABLE> #----------------------------- print T.table[ [T.caption['Cities I have Known'], T.tr[T.th['State'], T.th['Cities']] ] + [T.tr[ [T.th(k)] + [T.td(city) for city in sorted(states[k])]] for k in sorted(states.keys())]] #----------------------------- # salcheck - check for salaries import MySQLdb import cgi form = cgi.FieldStorage() if 'limit' in form: limit = int(form['limit'].value) else: limit = '' # There's not a good way to start an HTML/XML construct with stan # without completing it. print '<html><head><title>Salary Query</title></head><body>' print T.h1['Search'] print '<form>' print T.p['Enter minimum salary', T.input(type="text", name="limit", value=limit)] print T.input(type="submit") print '</form>' if limit: dbconn = MySQLdb.connect(db='somedb', host='server.host.dom', port=3306, user='username', passwd='password') cursor = dbconn.cursor() cursor.execute(""" SELECT name, salary FROM employees WHERE salary > %s""", (limit,)) print T.h1["Results"] print "<TABLE BORDER=1>" for row in cursor.fetchall(): print T.tr[ [T.td(cell) for cell in row] ] print "</TABLE>\n"; cursor.close() dbconn.close() print '</body></html>' #----------------------------- |
#----------------------------- url = "http://python.org/pypi" print "Location: %s\n" % url raise SystemExit #----------------------------- # oreobounce - set a cookie and redirect the browser import Cookie import time c = Cookie.SimpleCookie() c['filling'] = 'vanilla cr?me' now = time.time() future = now + 3*(60*60*24*30) # 3 months expire_date = time.strftime('%a %d %b %Y %H:%M:%S GMT', future) c['filling']['expires'] = expire_date c['filling']['domain'] = '.python.org' whither = "http://somewhere.python.org/nonesuch.html" # Prints the cookie header print 'Status: 302 Moved Temporarily' print c print 'Location:', whither print #----------------------------- #Status: 302 Moved Temporarily #Set-Cookie: filling=vanilla%20cr%E4me; domain=.perl.com; # expires=Tue, 21-Jul-1998 11:58:55 GMT #Location: http://somewhere.perl.com/nonesuch.html #----------------------------- # os_snipe - redirect to a Jargon File entry about current OS import os, re dir = 'http://www.wins.uva.nl/%7Emes/jargon' matches = [ (r'Mac', 'm/Macintrash.html'), (r'Win(dows )?NT', 'e/evilandrude.html'), (r'Win|MSIE|WebTV', 'm/MicroslothWindows.html'), (r'Linux', 'l/Linux.html'), (r'HP-UX', 'h/HP-SUX.html'), (r'SunOS', 's/ScumOS.html'), (None, 'a/AppendixB.html'), ] for regex, page in matches: if not regex: # default break if re.search(regex, os.environ['HTTP_USER_AGENT']): break print 'Location: %s/%s\n' % (dir, page) #----------------------------- # There's no special way to print headers print 'Status: 204 No response' print #----------------------------- #Status: 204 No response #----------------------------- |
# download the following standalone program #!/usr/bin/python # dummyhttpd - start a HTTP daemon and print what the client sends import SocketServer # or use BaseHTTPServer, SimpleHTTPServer, CGIHTTPServer def adr_str(adr): return "%s:%d" % adr class RequestHandler(SocketServer.BaseRequestHandler): def handle(self): print "client access from %s" % adr_str(self.client_address) print self.request.recv(10000) self.request.send("Content-Type: text/plain\n" "Server: dymmyhttpd/1.0.0\n" "\n...\n") self.request.close() adr = ('127.0.0.1', 8001) print "Please contact me at <http://%s>" % adr_str(adr) server = SocketServer.TCPServer(adr, RequestHandler) server.serve_forever() server.server_close() |
import Cookie cookies = Cookie.SimpleCookie() # SimpleCookie is more secure, but does not support all characters. cookies["preference-name"] = "whatever you'd like" print cookies # download the following standalone program #!/usr/bin/python # ic_cookies - sample CGI script that uses a cookie import cgi import os import Cookie import datetime cookname = "favorite-ice-cream" # SimpleCookie does not support blanks fieldname = "flavor" cookies = Cookie.SimpleCookie(os.environ.get("HTTP_COOKIE","")) if cookies.has_key(cookname): favorite = cookies[cookname].value else: favorite = "mint" form = cgi.FieldStorage() if not form.has_key(fieldname): print "Content-Type: text/html" print "\n" print "<html><body>" print "<h1>Hello Ice Cream</h1>" print "<form>" print 'Please select a flavor: <input type="text" name="%s" value="%s" />' % ( fieldname, favorite ) print "</form>" print "<hr />" print "</body></html>" else: favorite = form[fieldname].value cookies[cookname] = favorite expire = datetime.datetime.now() + datetime.timedelta(730) cookies[cookname]["expires"] = expire.strftime("%a, %d %b %Y %H:00:00 GMT") cookies[cookname]["path"] = "/" print "Content-Type: text/html" print cookies print "\n" print "<html><body>" print "<h1>Hello Ice Cream</h1>" print "<p>You chose as your favorite flavor \"%s\"</p>" % favorite print "</body></html>" |
# @@INCOMPLETE@@ # @@INCOMPLETE@@ |
# @@INCOMPLETE@@ # @@INCOMPLETE@@ |
#----------------------------- # first open and exclusively lock the file import os, cgi, fcntl, cPickle fh = open('/tmp/formlog', 'ab') fcntl.flock(fh.fileno(), fcntl.LOCK_EX) form = cgi.FieldStorage() # This doesn't produce a readable file; we copy the environment so # that we save a plain dictionary (os.environ is a dictionary-like # object). cPickle.dump((form, os.environ.copy()) fh) fh.close() #----------------------------- import cgi, smtplib, sys form = cgi.FieldStorage() email = """\ From: %S To: hisname@hishost.com Subject: mailed form submission """ % sys.argv[0] for key in form: values = form[key] if not isinstance(values, list): value = [values.value] else: value = [v.value for v in values] for item in values: email += '\n%s: %s' % (key, value) server = smtplib.SMTP('localhost') server.sendmail(sys.argv[0], ['hisname@hishost.com'], email) server.quit() #----------------------------- # @@INCOMPLETE@@ I don't get the point of these: # param("_timestamp", scalar localtime); # param("_environs", %ENV); #----------------------------- import fcntl, cPickle fh = open('/tmp/formlog', 'rb') fcntl.flock(fh.fileno(), fcntl.LOCK_SH) count = 0 while True: try: form, environ = cPickle.load(fh) except EOFError: break if environ.get('REMOTE_HOST').endswith('perl.com'): continue if 'items requested' in form: count += int(form['items requested'].value) print 'Total orders:', count #----------------------------- |
# @@INCOMPLETE@@ # @@INCOMPLETE@@ |