7 Web Programming

7.5 Forms with User Input

In many applications, dynamic web pages should not only depend on the environment of the web server but also on the input provided by the client (i.e., the user contacting the server via its browser). In principle, this is possible since HTML includes also elements for user input (text fields, buttons, etc) which is sent to the web server when requesting a document. How can we access the user input in a CGI program running on the server? The whole purpose of the Common Gateway Interface is to create a way to send information to the server and from the browswer, hence the name Common Gateway. Fortunately, it is not necessary to know all the details of CGI since the library HTML.Base defines an abstraction layer to provide a comfortable access to user inputs. This abstraction layer exploits the functional and logic features of Curry and will be explained in this section.

The library HTML.Base contains definitions of various input elements for HTML forms. For instance, the element “textfield” defines an HTML input element where the user can type a line of text:

textfield :: CgiRef -> String -> HtmlExp

The second argument is the initial contents and the first argument is the reference to this element (CGI reference). The reference is used in the CGI program to access the user’s actual input when computing an answer to this form. Now, how is the type CgiRef defined? The surprising answer is: the type is abstract (i.e., its constructors are not exported by the HTML library) since it is not necessary to know any constructor! It is sufficient to use a logic variable when using a text field in an HTML form. For instance, we can define a form containing a string and an input field as follows:

rdForm = return $ form "Question"
          [htxt "Enter a string: ", textfield tref ""]
 where tref free

A CgiRef variable serves as a reference to the corresponding input field to access the user’s input. Raw CGI requires concrete strings as references (attribute “name” of “input” tags) which is error-prone (since typos in these strings lead to run-time errors). However, the concrete strings are not important, and so the logic variables are sufficient. It is only important to use them when computing the answer to the client. For this purpose, the library HTML.Base defines a CGI environment as a mapping from CGI references to strings:

type CgiEnv = CgiRef -> String

A CGI environment is used to collect the input of the user when computing the response. The computation of the response is done by an event handler that is attached to each button for submitting a form to the web server. For this purpose, the library HTML.Base defines the type of event handlers as

type HtmlHandler = CgiEnv -> IO HtmlForm

i.e., an event handler is called with the current CGI environment and yields an I/O action that returns a form to be sent back to the client. Thus, the library HTML.Base contains the following type definition for a button to submit forms:

button :: String -> HtmlHandler -> HtmlExp

The first argument is the text shown on the button and the second argument is the event handler called when the user clicks this submit button.

The actual event handlers can simply be defined as local functions attached to forms so that the CgiRef variables are in scope and need not be passed. To see a simple but complete example, we show the specification of a form where the user can enter a string and choose between two actions (reverse or duplicate the string) by two submit buttons (see Figure 7.1) [Browse Program][Download Program]:

Figure 7.1: A simple string reverse/duplication form
rdForm :: IO HtmlForm
rdForm = return $ form "Question"
           [htxt "Enter a string: ", textfield tref "", hrule,
            button "Reverse string"   revhandler,
            button "Duplicate string" duphandler]
 where
   tref free
   revhandler env = return $ form "Answer"
     [h1 [htxt $ "Reversed input: " ++ reverse (env tref)]]
   duphandler env = return $ form "Answer"
     [h1 [htxt $ "Duplicated input: " ++ env tref ++ env tref]]

Note the simplicity of retrieving values entered into the form: since the event handlers are called with the appropriate environment containing these values (parameter “env”), they can easily access these values by applying the environment to the appropriate CGI reference, like “(env tref)”.