www.gibmonks.com

Main Page




Previous Page
Next Page

[Page 928 (continued)]

19.11. Using XHTML Forms to Send Input

Having a client enter input directly into a URL is not a user-friendly approach. Fortunately, XHTML provides the ability to include forms on Web pages that provide a more intuitive way for users to input information to be sent to a CGI script.


[Page 929]

XHTML form Element

The form element encloses an XHTML form. The form element generally takes two attributes. The first is action, which specifies the server resource to execute when the user submits the form. For our purposes, the action usually will be a CGI script that processes the form's data. The second attribute used in the form element is method, which identifies the type of HTTP request (i.e., get or post) to use when the browser submits the form to the Web server. In this section, we show examples using both get and post requests to illustrate them in detail.

An XHTML form may contain any number of elements. Figure 19.10 gives a brief description of several form elements.


[Page 931]

Figure 19.10. XHTML form elements.

Element name

type attribute value (for input elements)

Description

input

text

Provides a single-line text field for text input.

password

Like text, but each character typed by the user appears as an asterisk (*).

checkbox

Displays a checkbox that can be checked (TRue) or unchecked (false).

radio

Radio buttons are like checkboxes, except that only one radio button in a group of radio buttons can be selected at a time.

button

A push button.

submit

A push button that submits form data according to the form's action.

image

The same as submit, but displays an image rather than a push button.

reset

A push button that resets form fields to their default values.

file

Displays a text field and button that allow the user to specify a file to upload to a Web server. When clicked, the button opens a file dialog that allows the user to select a file.

hidden

Hidden form data that can be used by the form handler on the server. These inputs are not visible to the user.

select

Drop-down menu or selection box. This element is used with the option element to specify a series of selectable items.

textarea

This is a multiline text field in which text can be input or displayed.


Using get Request

Figure 19.11 demonstrates a basic XHTML form using the HTTP get method. The form is output in lines 3436 with the form element. Notice that attribute method has the value "get" and attribute action has the value "getquery.cgi" (i.e., the script actually calls itself to handle the form data, once it is submitted).

Figure 19.11. Using get method with an XHTML form.
(This item is displayed on pages 932 - 934 in the print version)

 1  // Fig. 19.11: getquery.cpp
 2  // Demonstrates GET method with XHTML form.
 3  #include <iostream>
 4  using std::cout;
 5
 6  #include <string>
 7  using std::string;
 8
 9  #include <cstdlib>
10  using std::getenv;
11
12  int main()
13  {
14     string nameString = "";
15     string wordString = "";
16     string query = "";
17
18     if ( getenv( "QUERY_STRING" ) ) // QUERY_STRING variable exists    
19        query = getenv( "QUERY_STRING" ); // retrieve QUERY_STRING value
20
21     cout << "Content-Type: text/html\n\n"; // output HTTP header
22
23     // output XML declaration and DOCTYPE
24     cout << "<?xml version = \"1.0\"?>"
25        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
26        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
27
28     // output html element and some of its contents
29     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
30        << "<head><title>Using GET with Forms</title></head><body>";
31
32     // output xhtml form
33     cout << "<p>Enter one of your favorite words here:</p>"
34        << "<form method = \"get\" action = \"getquery.cgi\">"
35        << "<input type = \"text\" name = \"word\"/>"
36        << "<input type = \"submit\" value = \"Submit Word\"/></form>";
37
38     if ( query == "" ) // query is empty
39        cout << "<p>Please enter a word.</p>";
40     else // user entered query string
41     {
42        int wordLocation = query.find_first_of( "word=" ) + 5;
43        wordString = query.substr( wordLocation );            
44
45        if ( wordString == "" ) // no word was entered
46           cout << "<p>Please enter a word.</p>";
47        else // word was entered
48           cout << "<p>Your word is: " << wordString << "</p>";
49     } // end else
50
51     cout << "</body></html>";
52     return 0;
53  } // end main

The form contains two input fields. The first (line 35) is a single-line text field (type = "text") named word. The second (line 36) displays a button, labeled Submit Word (value = "Submit Word"), to submit the form data.

The first time the script is executed, there should be no value in QUERY_STRING (unless the user has appended the query string to the URL). [Note: Recall that on some servers QUERY_STRING may not even exist when the query string is empty.] Once the user enters a word into the word text field and clicks Submit Word, the script is requested again. This time, the name of the input field (word) and the value entered by the user are placed in the QUERY_STRING environment variable. That is, if the user enters the word "technology" and clicks Submit Word, QUERY_STRING is assigned the value word=technology. Note that the query string is also appended to the URL in the browser's Address field with a question mark (?) in front of it.


[Page 934]

During the second execution of the script, the query string is decoded. Lines 42 uses string method find_first_of to search query for the first occurrence of word=, which returns an integer value corresponding to the location in the string where the first match was found. Line 42 then adds 5 to the value returned by find_first_of to set wordLocation equal to the position in the string containing the first character of the user's favorite word. Function substr (line 43) returns the remainder of the string starting at wordLocation. Line 43 then assigns this string to wordString. Line 45 determines whether the user entered a word. If so, line 48 outputs the word entered by the user.

Using post Request

The two preceding examples used get to pass data to the CGI scripts through an environment variable (i.e., QUERY_STRING). Web browsers typically interact with Web servers by submitting forms using HTTP post. CGI programs read the contents of post requests using standard input. For comparison purposes, let us now reimplement the application of Fig. 19.11, using the post method (as in Fig. 19.12). Notice that the code in the two figures is virtually identical. The XHTML form (lines 4345) indicates that we are now using the post method to submit the form data.

Figure 19.12. Using post method with an XHTML form.
(This item is displayed on pages 935 - 937 in the print version)

 1  // Fig. 19.12: post.cpp
 2  // Demonstrates POST method with XHTML form.
 3  #include <iostream>
 4  using std::cout;
 5  using std::cin;
 6
 7  #include <string>
 8  using std::string;
 9
10  #include <cstdlib>
11  using std::getenv;
12  using std::atoi;
13
14  int main()
15  {
16     char postString[ 1024 ] = ""; // variable to hold POST data
17     string dataString = "";
18     string nameString = "";
19     string wordString = "";
20     int contentLength = 0;
21
22     // content was submitted
23     if ( getenv( "CONTENT_LENGTH" ) )
24     {
25        contentLength = atoi( getenv( "CONTENT_LENGTH" ) );
26        cin.read( postString, contentLength );             
27        dataString = postString;
28     } // end if
29
30     cout << "Content-Type: text/html\n\n"; // output header
31
32     // output XML declaration and DOCTYPE
33     cout << "<?xml version = \"1.0\"?>"
34        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
35        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
36
37     // output XHTML element and some of its contents
38     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
39        << "<head><title>Using POST with Forms</title></head><body>";
40
41     // output XHTML form
42     cout << "<p>Enter one of your favorite words here:</p>"
43        << "<form method = \"post\" action = \"post.cgi\">"
44        << "<input type = \"text\" name = \"word\" />"
45        << "<input type = \"submit\" value = \"Submit Word\" /></form>";
46
47     // data was sent using POST
48     if ( contentLength > 0 )
49     {
50        int nameLocation = dataString.find_first_of( "word=" ) + 5;
51        int endLocation = dataString.find_first_of( "&" ) - 1;
52
53        // retrieve entered word
54        wordString = dataString.substr(
55           nameLocation, endLocation - nameLocation );
56
57        if ( wordString == "" ) // no data was entered in text field
58           cout << "<p>Please enter a word.</p>";
59        else // output word
60           cout << "<p>Your word is: " << wordString << "</p>";
61     } // end if
62     else // no data was sent
63        cout << "<p>Please enter a word.</p>";
64
65     cout << "</body></html>";
66     return 0;
67  } // end main


[Page 937]

The Web server sends post data to a CGI script via standard input. The data is encoded (i.e., formatted) just as in QUERY_STRING (that is, with name-value pairs connected by equals signs and ampersands), but the QUERY_STRING environment variable is not set. Instead, the post method sets the environment variable CONTENT_LENGTH, to indicate the number of characters of data that were sent in a post request.

The CGI script uses the value of the CONTENT_LENGTH environment variable to process the correct amount of data. Line 23 determines whether CONTENT_LENGTH contains a value. If so, line 25 reads in the value and converts it to an integer by calling <cstdlib> function atoi. Line 26 calls function cin.read to read characters from standard input and stores the characters in array postString. Line 27 converts postString's data to a string by assigning it to dataString.

In earlier chapters, we read data from standard input using an expression such as

cin >> data;


[Page 938]

The same approach might work in our CGI script as a replacement for the cin.read statement. Recall that cin reads data from standard input up to and including the first newline character, space or tab, whichever comes first. The CGI specification (freely available at cgi-spec.golux.com/cgi-120-00a.html) does not require a newline to be appended after the last name-value pair. Although some browsers append a newline or EOF, they are not required to do so. If cin is used with a browser that sends only the name-value pairs (as per the CGI specification), cin must wait for a newline that will never arrive. In this case, the server eventually "times out" and the CGI script terminates. Therefore, cin.read is preferred over cin, because the programmer can specify exactly how much data to read.

The CGI scripts in this section, while useful for explaining how get and post operate, do not include many of the features described in the CGI specification. For example, if we enter the words didn't translate into the text field and click the submit button, the script informs us that our word is didn%27t+translate.

What has happened here? Web browsers "URL encode" the XHTML form data they send. This means that spaces are replaced with plus signs, and other symbols (e.g., apostrophes) are translated into their ASCII value in hexadecimal format and preceded with a percent sign. URL encoding is necessary because URLs cannot contain certain characters, such as spaces and apostrophes.


Previous Page
Next Page