What is CGI?
CGI Scripting is a type of server side programming that powers a lot of the useful sites on the web. CGI Scripts power search engines, online shopping sites, and many if not all news sites, discussion forums, blogs, etc.
Server Side means that the code runs on a remote server, and the only the output is sent to the client. So in the case of a google search, I first go to their homepage:
Google's pages are mostly simple HTML markup, but there are a few special statements that create a "Form", that is responsible for displaying the text box that you type your query into, and the buttons that you can press to begin your search. Some of the code that generates this form is displayed below. Do you see the line where "name=q" is? That's the text box that you type into. The buttons are the pretty obvious last couple lines. The really important one is hiding at the top:
< form action='/search' name=f>Action essentially tells the form what script to submit it's input to, so this is really key if you want a CGI script that interacts with a user.
< form action="/search" name=f>
< input type=hidden name=oe value="UTF-8">
< input maxLength=256 size=55 name=q value="">
< input type=submit value="Google Search" name=btnG>
< input type=submit value="I'm Feeling Lucky" name=btnI>
Now when you click the button on that form to submit your search string, a CGI script (which I don't have access to so I can't show you), takes that string and runs the search. Then from your search results, the CGI script on the server takes those results and formats them as HTML, and outputs them to you.
Now not all CGI scripts are like this, some are run everytime you access a page, without you pressing any buttons or inputing any data. We'll have an example or two in a little bit. For now I hope that this helps give those of you who are looking into CGI scripting for the first time some idea of what you'll be trying to accomplish with your scripts.
A (very) simple script:
First let's take a very quick look at test.py:#!/usr/bin/python print "Content-type: text/html" print print "<title>CGI 101</title>" print "<h1>A First CGI Example</h1>" print "<P>Hello, CGI World!</p>"
Initial Content
Before printing anything else in your CGI script you should be certain to print the following "special" lines:print "Content-type: text/html\n" print # I'm a blank line
Debugging and Coding Tips
To simplify debugging there are several things you can do. Old school CGI scriptors, especially from the Perl camp we'll suggest that you do something like this:import sys sys.stderr = sys.stdout
import cgitb; cgitb.enable()
One last thing to keep in mind:Always run your script at the commandline before trying it in your browser! If your script has any major syntax errors in it(incorrect indentation, missing modules and misspellings) it will simply refuse to run and you will see:
500: Internal Server Error
... rather then the friendly and exciting CGI script output you were expecting. cgitb and other techniques will handle runtime errors, but not syntax errors, those you have to deal with before cgitb can be of any help.
So what errors will I actually see? Well, you won't see syntax errors, so you won't see something like this:
# Bad: This will cause your CGI script to not run at all error = "a string" + 7 # Okay error = "a string" + str(7) # Notice how it's just a simple syntax error? # Run your code through the interpreter before hand to check for these errors.
But this will show up in your browser as an error(in cgitb or whatever):
# This will generate an error
# but it will at least show output in your browser
file = open("file_that_does_not_exist.txt","r")
# Essentially cgitb is useful for debuggin logical problems in your code,
# and not syntax problems.
A "no-input" example
This CGI script just prints the current time (on the server) that you asked for the page.
Here's the code:
#!/usr/bin/python import cgitb cgitb.enable() print "Content-type: text/html" print import time print "<HTML>" print "<HEAD>" print "<TITLE>Penzilla.net: What is the Time? Example</TITLE>" print "</HEAD>" print "<BODY>" print "<H2>Penzilla.net What is the Time?(wittime.py) Example:</h2>" print "<P>Penzilla thinks that it is: %s</P>" % time.ctime() print "</BODY>" print "</HTML>"
Click here to test out wittime.py
A Game: Rock Paper Scissors Spock Lizard
Rock Paper Scissors Spock Lizard is a variation on the classic game or Rock Paper Scissors. The addition of two new "signs" makes the game a little more interesting and a little harder to predict. The code is not the most exciting in the world, and it's pretty repetitive, so I'm including links to just download and check the code out at your leisure.
The Required HTML input pageThe python code / CGI Script
Try playing the game here: http://www.penzilla.net/tutorials/python/cgi/rpssl.html
Sorting IP Addresses
I wrote the following program to help out a friend who wanted to look at his web traffic a bit. He had a number of php hit counters that stored the ip address of anyone who visited his site. He was interested in things like who visited his site most and things like that.
The following simple script grabs these hits[1-8].txt files and read's all the ip addresses from them. It then sorts the IP addresses and counts the number of times each address occurs.
It is designed to run as a CGI to let you check this information from your browser.
#!/usr/bin/python """ Sorts Dotted Decimal IP Addresses xxx.yyy.zzz.www """ import cgi, cgitb cgitb.enable() # Useful for a little error checking import string class IP: def __init__(self, address_string=None): self.a,self.b,self.c,self.d = -1,-1,-1,-1 if address_string!=None: self.set(address_string) def set( self, address ): quads = address.split(".") try: self.a = int(quads[0]) self.b = int(quads[1]) self.c = int(quads[2]) self.d = int(quads[3]) except ValueError: self.a,self.b,self.c,self.d=-1,-1,-1,-1 def __cmp__(self, addr2): if self.greaterthen(addr2): return 1 elif self.equalto(addr2): return 0 else: return -1 def greaterthen( self, addr2 ): if self.a > addr2.a: return 1 elif self.a == addr2.a and self.b > addr2.b: return 1 elif self.b == addr2.b and self.c > addr2.c: return 1 elif self.c == addr2.c and self.d > addr2.d: return 1 else: return 0 def equalto( self, addr2 ): if self.a == addr2.a and \ self.b == addr2.b and \ self.c == addr2.c and \ self.d == addr2.d: return 1 else: return 0 def __str__( self ): string = str(self.a) + "." string += str(self.b) + "." string += str(self.c) + "." string += str(self.d) return string def __hash__( self ): num = self.a * 1000 num += self.b * 100 num += self.c * 10 num += self.d return int(num) def __repr__( self ): string = str(self.a) + "." string += str(self.b) + "." string += str(self.c) + "." string += str(self.d) return string if __name__=="__main__": print "Content-Type: text/html" print # Blank Line file_numbers = [1,2,3,4,5,6,7,8] filenames = [] for each in file_numbers: filenames.append("../hits"+str(each)+".txt") print "<html>" print "<HEAD>" print "<TITLE>" print "IP Stats" print "</TITLE>" print "<body>" print "<H1>IP Stats</H1>" for filename in filenames: # 1). Read in the file file = open(filename,"r") lines = file.readlines() # 2). Get the IP's addresses = {} for line in lines: if ( string.strip( line, string.whitespace )=='' ): continue temp = IP( line ) if temp in addresses.keys(): addresses[temp] += 1 else: addresses[temp] = 1 # 2). Sort the IP's keys = addresses.keys() keys.sort() # 3). Print a Table of Sorted Ip's print "<H2>","IP's in file:",filename,"</h2>" print "<table>" for key in keys: print "<tr>" print "<td>",key,"</td><td>", addresses[key],"</td>" print "</tr>" print "</table>" print "</body>" print "</html>"