Summary
I've been doing a lot of web programming lately. Although I've experimented with PHP, I keep migrating back to Python.
Advertisement
I've found PHP useful for some presentation-layer things, especially basics like standard headers and footers. And there are lots of web-specific functions in PHP, and a very large number of modules and applications available.
But as soon as the logic starts to get complex, I find Python to be easier to manage, probably because I've used it for so many years.
The problem with most languages when writing CGIs is testing. You usually have to move the CGI to a server and run it there in order to see what's going on, adding extra code to feed error information back to you. If you're trying to do rapid experimentation, this slows you down significantly.
Python does have a nice module for producing nicely-formatted and colored error output on a web page, which helps considerably. You just say:
import cgitb; cgitb.enable()
Also, you can run a Python CGI on the command line to detect syntax errors. But there isn't a built-in approach to feed test variables into a CGI, as if they were coming from a web page with a form on it.
To capture form variables from a page, Python has the cgi module. You use it like this:
form = cgi.FieldStorage()
Now form contains the names and values from the submitted page. If you run a cgi containing the above line from the command line, form will still be created, but it will be empty. Assuming there would be a way to populate it by hand for testing, I looked through the code in cgy.py and discovered that I could populate it this way:
for name, value in {
"name1" : "value1",
"name2" : "value2",
"name3" : "value3",
"name4" : "value4",
"name5" : "value5",
}.items():
form.list.append(cgi.MiniFieldStorage(name, value))
Now form contains the same information as if it were populated by submitting a form through the web.
You'll typically only want to load test data when you're experimenting on your local machine. Also, there are other configurations which will differ between your local machine and the server. For example, cgitb.enable() is very helpful on the server, but on your local machine it pours out all the html formatting, which isn't very helpful. And producing your own error messages on the server is different than on a local machine.
One approach is to have a flag that you change depending on whether you're running on a server or a local machine, but I didn't want to require any extra actions (details count). My approach was to look at the path for a directory that exists on the local machine but not on the server. So, for example, if the cgi lived on the local machine in a path that included "website," you can do this:
runningOnServer = "website" not in os.getcwd()
The "in" operation here is from Python 2.4 and is definitely one of my favorite improvements -- it checks whether a string appears within another string and is far more readable and intuitive than
os.getcwd().find("website") != -1
From then on, you just check runningOnServer when deciding what to do, like this:
if runningOnServer:
import cgitb; cgitb.enable()
You can also choose the way errors are reported:
def error(msg):
print "Content-type: text/html"
print
print "Error:", msg
sys.exit()
if not runningOnServer:
def error(msg):
print "Error:", msg
sys.exit()
And of course if it's not running on the server, you can populate the test data.
I do XML CGI in Python and use SSH and tail. XML and cgitb.enable() is problematic because you get the generic "xml is borked" message instead of the real error.
I also use a index.py?mime=plain/html/xml so that I can check output a bit easier. If you do pure XML work, you could add a XSLT stylesheet to the XML and get a pretty HTML report generated on the fly.
Server/Devbox checks are a bit risky. I checked for paths once and the hosting provider changed the whole path structure and did a copy/paste of my code. Whoops.. everything go 500.
Testing any CGI easily can be done in a few ways, but I have found that if the server executing the code is in the same language as the CGI then all you do is debug the server and run the CGI on it.
Using BaseHTTPServer package in python you can easily while a full HTTP server in python and then use python debugger of choice on the server and put a breakpoint in processing the class based on BaseHTTPRequestHandler.