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.


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.


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 4 using std::cout; 5 6 #include 7 using std::string; 8 9 #include 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 "; // output HTTP header 22 23 // output XML declaration and DOCTYPE 24 cout << "" 25 << " 26 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 27 28 // output html element and some of its contents 29 cout << "" 30 << "Using GET with Forms; 31 32 // output xhtml form 33 cout << "

Enter one of your favorite words here:

" 34 << "

" 35 << "" 36 << ""

; 37 38 if ( query == "" ) // query is empty 39 cout << "

Please enter a word.

"; 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 << "

Please enter a word.

"; 47 else // word was entered 48 cout << "

Your word is: " << wordString << "

"; 49 } // end else 50 51 cout << ""; 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.


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 4 using std::cout; 5 using std::cin; 6 7 #include 8 using std::string; 9 10 #include 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 "; // output header 31 32 // output XML declaration and DOCTYPE 33 cout << "" 34 << " 35 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 36 37 // output XHTML element and some of its contents 38 cout << "" 39 << "Using POST with Forms"; 40 41 // output XHTML form 42 cout << "

Enter one of your favorite words here:

" 43 << "

" 44 << "" 45 << ""

; 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 << "

Please enter a word.

"; 59 else // output word 60 cout << "

Your word is: " << wordString << "

"; 61 } // end if 62 else // no data was sent 63 cout << "

Please enter a word.

"; 64 65 cout << ""; 66 return 0; 67 } // end main

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 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;

 


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.

Категории