Let’s get back
to writing server-side code. As anyone who’s ever surfed
the Web knows, web pages usually consist of more than simple text.
Example 15-4
is a Python CGI script
that prints an
HTML tag
in its output to produce a graphic image in the client browser. This
example isn’t very Python-specific, but note that just as for simple
HTML files, the image file (
ppsmall.gif
, one level
up from the script file) lives on and is downloaded from the server
machine when the browser interprets the output of this script to render
the reply page (even if the server’s machine is the same as the
client’s).
Example 15-4. PP4E\Internet\Web\cgi-bin\tutor1.py
#!/usr/bin/python
text = """Content-type: text/htmlRead Programming Python (152 page) Page 152 Read Book Online,Top Vampire Books Read Online Free A Second CGI Script
Hello, CGI World!
"""
print(text)
Notice the use of the triple-quoted string block here; the entire
HTML string is sent to the browser in one fell swoop, with theprint
call statement at the end. Be sure that
the blank line between the Content-type header and the first HTML is
truly blank in the string (it may fail in some browsers if you have any
spaces or tabs on that line). If both client and server are functional,
a page that looks like
Figure 15-4
will be generated
when this script is referenced and run.
So far, our CGI scripts have been putting out canned HTML that
could have just as easily been stored in an HTML file. But because CGI
scripts are executable programs, they can also be used to generate HTML
on the fly, dynamically—even, possibly, in response to a particular set
of user inputs sent to the script. That’s the whole purpose of CGI
scripts, after all. Let’s start using this to better advantage now, and
write a Python script that builds up response HTML programmatically,
listed in
Example 15-5
.
Figure 15-4. A page with an image generated by tutor1.py
Example 15-5. PP4E\Internet\Web\cgi-bin\tutor2.py
#!/usr/bin/python
print("""Content-type: text/htmlRead Programming Python (152 page) Page 152 Read Book Online,Top Vampire Books Read Online Free A Third CGI Script
Hello, CGI World!
%d.%d | ' % (i, j))
Despite all the tags, this really is Python code—the
tutor2.py
script uses triple-quoted strings to
embed blocks of HTML again. But this time, the script also uses nested
Pythonfor
loops to dynamically
generate part of the HTML that is sent to the browser. Specifically, it
emits HTML to lay out a two-dimensional table in the middle of a page,
as shown in
Figure 15-5
.
Figure 15-5. A page with a table generated by tutor2.py
Each row in the table displays a “row.column” pair, as generated
by the executing Python script. If you’re curious how the generated HTML
looks, select your browser’s View Source option after you’ve accessed
this page. It’s a single HTML page composed of the HTML generated by the
firstprint
in the script, then thefor
loops, and finally the lastprint
. In other words, the
concatenation of this script’s output is an HTML document with
headers.
The script
in
Example 15-5
generates HTML table tags. Again, we’re not out to learn HTML here,
but we’ll take a quick look just so that you can make sense of this
book’s examples. Tables are declared by the text between
tags in HTML. Typically, a
and
table’s text in turn declares the contents of each table row between
tags and each column within a
and
row between
tags. The loops in our script
and
build up HTML to declare five rows of four columns each by printing
the appropriate tags, with the current row and column number as column
values.
For instance, here is part of the script’s output, defining the
first two rows (to see the full output, run the script standalone from
a system command line, or select your browser’s View Source
option):
0.0 | 0.1 | 0.2 | 0.3 |
1.0 | 1.1 | 1.2 | 1.3 |
Other table tags and options let us specify a row title CGI scripts are That description Example 15-6. PP4E\Internet\Web\tutor3.html Enter your name: tutor3.html Figure 15-6. A simple form page generated by tutor3.html We won’t go into all the The Input controls are As we’ll see in later examples, other input tag options Forms also An alternative With The Notice that the Example 15-7. PP4E\Internet\Web\tutor3-minimal.html Enter your name: It may help to remember that URLs embedded in form action tags On the other hand, URLs submitted outside of a page (e.g., typed So far, we’ve Example 15-8. PP4E\Internet\Web\cgi-bin\tutor3.py %s As before, this Python CGI script prints HTML to generate a Luckily, this is automatic in Python: a call to the standard Scripts should call Before exiting, this script prints HTML to produce a result page Hello, King Arthur. In a browser, the output is rendered into a page like the one in Figure 15-7. tutor3.py result for parameters in a form Notice that the URL But there’s a catch here: where does the input field’s value For instance, we can skip filling out the input form page In this URL, a value for the input named Figure 15-8. tutor3.py result for parameters in a URL In fact, HTML forms that specify the Generally, any CGI script can be invoked either by filling out When CGI scripts are invoked with explicit input parameters this Incidentally, if you clear out the name input field in the form Figure 15-9. An empty name field producing an error page In general, CGI scripts must check to see whether any inputs are
(
), lay out borders, and
so on. We’ll use more table syntax to lay out forms in a uniform
fashion later in
this tutorial.
great at generating HTML on the fly like this, but they
are also commonly used to implement interaction with a user typing at a
web browser. As described earlier in this chapter, web interactions
usually involve a two-step process and two distinct web pages: you fill
out an input form page and press Submit, and a reply page eventually
comes back. In between, a CGI script processes the form input.
sounds simple enough, but the process of collecting user
inputs requires an understanding of a special HTML tag,. Let’s look at the
implementation of a simple web interaction to see forms at work.
First, we need to define a form page for the user to fill out, as
shown in
Example 15-6
.A first user interaction: forms
is a simple HTML file, not a
CGI script (though its contents could be printed from a script as
well). When this file is accessed, all the text between itsand
tags generates the input
fields and Submit button shown in
Figure 15-6
.
details behind coding HTML forms, but a few highlights
are worth underscoring. The following occurs within a form’s HTML
code:
form’saction
option gives the URL of a CGI script that will be invoked to
process submitted form data. This is the link from a form to its
handler
program—
in this
case, a program called
tutor3.py
in the
cgi-bin
subdirectory of the locally running
server’s working directory. Theaction
option is the equivalent ofcommand
options in tkinter buttons—it’s where a callback handler (here,
a remote handler script) is registered to the browser and
server.
specified with nested
tags. In this example,
input tags have two key options. Thetype
option accepts values such astext
for text fields andsubmit
for a Submit button
(which sends data to the server and is labeled “Submit Query” by
default). Thename
option is the hook
used to identify the entered value by key, once all the form
data reaches the server. For instance, the server-side CGI
script we’ll see in a moment uses the stringuser
as a key to get the data typed
into this form’s text field.
can specify initial values (value=X
), display-only mode (readonly
), and so on. As we’ll also
see later, other inputtype
option
values may transmit hidden data that embeds state information in
pages (type=hidden
),
reinitializes fields (type=reset
), or makes multiple-choice
buttons (type=checkbox
).get
andpost
include amethod
option to specify the encoding
style to be used to send data over a socket to the target server
machine. Here, we use thepost
style, which contacts the server
and then ships it a stream of user input data in a separate
transmission over the socket.get
style ships input information to the server in a single
transmission step by appending user inputs to the query string
at the end of the URL used to invoke the script, usually after a?
character. Query parameters
were introduced earlier when we met URLs; we will put them to
use later in this section.get
, inputs
typically show up on the server in environment variables or as
arguments in the command line used to start the script. Withpost
, they must be read from
standard input and decoded. Because theget
method appends inputs to URLs, it
allows users to bookmark actions with parameters for later
submission (e.g., a link to a retail site, together with the
name of a particular item);post
is very generally meant for
sending data that is to be submitted once (e.g., comment
text).get
method is
usually considered more efficient, but it may be subject to
length limits in the operating system and is less secure
(parameters may be recorded in server logs, for instance).post
can handle larger inputs
and may be more secure in some scenarios, but it requires an
extra transmission. Luckily, Python’scgi
module transparently handles
either encoding style, so our CGI scripts don’t normally need to
know or care which is used.action
URL in
this example’s form spells out the full address for illustration.
Because the browser remembers where the enclosing HTML page came from,
it works the same with just the script’s filename, as shown in
Example 15-7
.A first user interaction: forms
and hyperlinks are directions to the browser first, not to the script.
The
tutor3.py
script itself doesn’t care which
URL form is used to trigger it—minimal or complete. In fact, all parts
of a URL through the script filename (and up to URL query parameters)
are used in the conversation between browser and HTTP server, before a
CGI script is ever spawned. As long as the browser knows which server
to contact, the URL will work.
into a browser’s address field or sent to the Pythonurllib.request
module we’ll revisit later)
usually must be completely specified, because there is no notion of a
prior page.
created only a static page with an input field. But the
Submit button on this page is loaded to work magic. When pressed, it
triggers the possibly remote program whose URL is listed in the form’saction
option, and passes this
program the input data typed by the user, according to the form’smethod
encoding style option. On
the server, a Python script is started to handle the form’s input data
while the user waits for a reply on the client; that script is shown
in
Example 15-8
.#!/usr/bin/python
"""
runs on the server, reads form input, prints HTML;
url=http://server-name/cgi-bin/tutor3.py
"""
import cgi
form = cgi.FieldStorage() # parse form data
print('Content-type: text/html') # plus blank line
html = """Greetings
"""
if not 'user' in form:
print(html % 'Who are you?')
else:
print(html % ('Hello, %s.' % form['user'].value))
response page in the client’s browser. But this script does a bit
more: it also uses the standardcgi
module to parse the input data entered by the user on the prior web
page (see
Figure 15-6
).
librarycgi
module’sFieldStorage
class
does all the work of extracting form data from the input stream and
environment variables, regardless of how that data was passed—in apost
style stream or inget
style parameters appended to the URL.
Inputs sent in both styles look the same to Python scripts.cgi.FieldStorage
only once and before
accessing any field values. When it is called, we get back an object
that looks like a dictionary—user input fields from the form (or URL)
show up as values of keys in this object. For example, in the script,form['user']
is an object whosevalue
attribute is a string
containing the text typed into the form’s text field. If you flip back
to the form page’s HTML, you’ll notice that the input field’sname
option wasuser
—the name in the form’s HTML has become
a key we use to fetch the input’s value from a dictionary. The object
returned byFieldStorage
supports
other dictionary operations, too—for instance, thein
expression may be used to check whether a
field is present in the input data.
that echoes back what the user typed into the form. Two
string-formatting expressions (%
)
are used to insert the input text into a reply string, and the reply
string into the triple-quoted HTML string block. The body of the
script’s output looks like this:Greetings
Figure 15-7
.
address of the script that generated this page shows up
at the top of the browser. We didn’t type this URL itself—it came from
theaction
tag of the prior page’sform
HTML. However, nothing is
stopping us from typing the script’s URL explicitly in our browser’s
address field to invoke the script, just as we did for our earlier CGI
script and HTML file examples.
come from if there is no form page? That is, if we type the CGI
script’s URL ourselves, how does the input field get filled in?
Earlier, when we talked about URL formats, I mentioned that theget
encoding scheme tacks input
parameters onto the end of URLs. When we type script addresses
explicitly, we can also append input values on the end of URLs, where
they serve the same purpose as
fields in forms. Moreover, the
Pythoncgi
module makes URL and
form inputs look identical to scripts.
completely and directly invoke our
tutor3.py
script by visiting a URL of this form (type this in your browser’s
address field):http://localhost/cgi-bin/tutor3.py?user=Brian
user
is specified explicitly, as if the user
had filled out the input page. When called this way, the only
constraint is that the parameter nameuser
must match the name expected by the
script (and hardcoded in the form’s HTML). We use just one parameter
here, but in general, URL parameters are typically introduced with a?
and are followed by one or morename=value
assignments, separated
by&
characters if there is
more than one.
Figure 15-8
shows the
response page we get after typing a URL with explicit inputs.get
encoding style also cause inputs to be
added to URLs this way. Try changing
Example 15-6
to usemethod=GET
, and submit the
form—
the name input in the form shows up
as a query parameter in the reply page address field, just like the
URL we manually entered in
Figure 15-8
. Forms can use
thepost
orget
style. Manually typed URLs with
parameters useget
.
and submitting a form page or by passing inputs at the end of a URL.
Although hand-coding parameters in URLs can become difficult for
scripts that expect many complex parameters, other programs can
automate the construction process.
way, it’s not too difficult to see their similarity to
functions
, albeit ones that live
remotely on the Net. Passing data to scripts in URLs is similar to
keyword arguments in Python functions, both operationally and
syntactically. In fact, some advanced web frameworks such as Zope make
the relationship between URLs and Python function calls even more
literal: URLs become more direct calls to Python functions.
input page (i.e., make it empty) and press Submit, theuser
name field becomes empty. More
accurately, the browser may not send this field along with the form
data at all, even though it is listed in the form layout HTML. The CGI
script detects such a missing field with the dictionaryin
expression and produces the page captured
in
Figure 15-9
in
response.
missing, partly because they might not be typed by a user in the form,
but also because there may be no form at all—input fields might not be
tacked onto the end of an explicitly typed or constructedget
-style URL. For instance, if we type the
script’s URL without any parameters at all—by omitting the text from
the?
and beyond, and visiting
http://localhost/cgi-bin/tutor3.py
with an
explicitly entered URL—we get this same error response page. Since we
can invoke any CGI through a form or URL, scripts must anticipate both
scenarios.Other books