Web forms with Transform 3.0 users' guide

On this page:


What is Transform?

Transform is a generic utility for processing HTML forms. Using Transform, you can have the values submitted via a form emailed to you or appended to a data file. Transform gives you control over the format of the information returned to you as well as the response you return to users.

Note:
This document assumes you know how to create HTML forms. Transform does not create forms for you; it only gives you a convenient way of dispensing submitted form information. Using your search engine of choice, you can find many HTML form tutorials online.

General overview of Transform

To use Transform, you create an HTML form and a corresponding Transform template file. The template file allows you to control the results of a submitted form. Each field in an HTML form has a name (e.g., NAME = "question"). In the corresponding plain text Transform template file, you control where the value of a form variable (e.g., a value entered by the user) is displayed by including the variable name in square brackets (e.g., [question]). See the example below.

A simple example

In the following HTML code for a form, three fields are defined: "name", "email", and "question" (i.e., NAME="name", NAME="email", and NAME="question"); view what this form would look like to a user.

  <html>
  <head>
  <title>A Sample Question Form</title>
  </head>
 
  <body>
  <h2>A Sample Question Form</h2>
  <hr>
 
  <form method = "POST" action = "transform_action_statement">
  <p>
  Enter your name:<br>
  <input NAME="name" size = 40>
  <br>
  Enter your email address:<br>
  <input NAME="email" size=40>
  <br>
  Enter your question:<br>
  <textarea NAME="question" rows=10 cols=40></textarea>
  <p>
  <input type="submit" value="Submit your question">
  </form>
 
  </body>
  </html>

To email the results of this form to a user whose email address is smith@indiana.edu and provide a "thank you" response to the user, you could create a corresponding template file like the following:

  # begin template file
  # Lines beginning with a # sign are considered comments.
  # The *email-response* line below specifies that this is the email-response
  # section of the template file. Other sections will be described later.
  # The other lines are just plain text with html form variable names
  # enclosed in [ ] where you want the values entered by the user
  # printed in the email message
  *email-response*
  To:smith@indiana.edu
  From:[email]
  Subject: Question from [name]
 
  Question from [name]
 
  Supplied email address is [email]
 
  See the question below:
 
  [question]
 
  # Now begin the *success-response* section that will be displayed to
  # the user. Because this is being sent back to the user's browser
  # it must be in the form of an html document
  *success-response*
  <html>
  <head>
  <title>Thank You</title>
  </head>
 
  <body>
  <h1>Thank You</h1>
 
  Your name is: [name]
  <br>
 
  You supplied the following email address: [email]
  <br>
 
  Your question was:
  <br>
 
  [question]
 
  </body>
  </html>
  # end template file

To see the results of this template file, fill out this form and submit it. This form will not actually send mail; it will just echo back what the response would look like.

Note that when the *success-response* section of the template file is echoed back to you, each form variable name in square brackets is replaced with the corresponding values supplied in the form (i.e., name, email, and question). If this template were operational, the *email-response* section would ensure that submitting the form would also send an email message.

Naming your form and template files

In general, you will have a single HTML form and a corresponding template file. Your HTML form files must have a .html extension, and the corresponding Transform template files must have a .tpl extension.

The HTML form and the template files should be in the same directory and have the same name except for the extension. For example, if your form were named send_comments.html, the corresponding template file would be send_comments.tpl. To avoid confusion, you may want to create one or more specific forms directories in your www directory, and place all forms and templates there.

Legal/illegal characters: When naming your forms and template files (and any directories that lead to them), you may use only the following characters: A-Z, a-z, 0-9, hyphen (-), underscore (_), and period (.). In addition, you may use tilde (~) and slash (/) when supplying paths to these files.

When a person fills out a web form processed by Transform, if HTML code is included, the code will display as HTML character code for security reasons.

Note:
In more advanced applications of Transform, you may have an HTML file that contains multiple forms, or a *success-response* or *error-response* section that contains an HTML form. In these cases, the name of the template file will not necessarily match any HTML file. Make sure you point to the right template file in the form action statement.

Installing Transform in your account

To have Transform process your HTML forms, you must install Transform in your own Webserve account. To install Transform, log into your account using a SSH secure shell client, such as PuTTY. For more about installing or obtaining PuTTY, see How do I use PuTTY to connect to Webserve?

Once logged into your account, type cd www to change to your www web document directory. Then, type tf_install.

You should install Transform 3.0 into any subdirectory where you have forms by typing tf_install from within that directory.

The tf_install command does the following:

  • It creates a tf_support directory in your login directory, unless it already exists. Transform will use this directory as needed to store files when processing your forms.
  • It copies a file called transform.cgi into the current directory (i.e., the same directory you are in when you type tf_install). You will point to this file in the form action statement in your form.
Notes:
  • Transform will append to the files in your account immediately when using an *append-response* section in your template.
  • You may install multiple copies of transform.cgi in different directories if you need to use special access control mechanisms; see Authentication: Controlling Access to Your Forms and Documents.
  • transform.cgi is not actually the Transform program; it's just a stub that points to it. Thus, you will automatically use new versions of Transform as they're installed.

Setting the form action to point to Transform

When a user submits data through an HTML form, the data goes to an application on the web server. This application reads the form data and does something with it. Transform is one such application. To use Transform, you must indicate in your form that you want Transform to receive and process your form data. In some cases, you must also specify the location of your template file; this is the purpose of the action = string in the HTML <form> statement that begins a form.

Pointing to Transform installed in your account

Simple method

In the simplest case where your form and template files have the same name (except for the extension) and are in the same directory, the HTML statement that begins the form and specifies what application should process the form can be:

On www.indiana.edu:

  <form method = "POST" action = "http://www.indiana.edu/~username/transform.cgi">

On www.iupui.edu (~username accounts only):

  <form method = "POST" action = "http://www.iupui.edu/~username/transform.cgi">

When someone submits your HTML form, Transform will know the location of your form, and can thus derive the location of your template file if it has the same name and is in the same directory. The statement breaks down as follows:

  • <form begins the form.
  • Using method = "POST" will post data. Always use method = "POST" when using Transform in HTML forms. For more, see URIs, Addressability, and the use of HTTP GET and POST from the W3C.
  • action = specifies where to send form data. In this case, http://www.indiana.edu/~username/transform.cgi or http://www.iupui.edu/~username/transform.cgi.

    This statement essentially provides a URL to transform.cgi in your account. You build this URL just as you would build a URL to a document in your web directory using a tilde (~) before your account name. (Thus, if you issued the tf_install command in some subdirectory of your web directory, you would have to include additional directory path information in the URL.)

    If you have installed Transform in every directory where you have a form, you can use a relative link to transform.cgi rather than the entire path. Your form action statement for either campus would then read, <form method = "POST" action = "transform.cgi">.

    For more, see Authentication: Controlling access to your forms and documents. Although this describes controlling access to documents in your web directory, the information also applies to transform.cgi in your account, because it is installed in your web directory.

Complete method

In cases where you have multiple forms per HTML file, or a form in a *success-response* or *error-response* section, you must specify the exact location of the template file. Otherwise, Transform won't find your template file and will report an error. This method is similar to the one described above, except that you must supply a path to the template file:

  <form method = "POST" action = "http://www.indiana.edu/~username/transform.cgi?template_path">

or

  <form method = "POST" action = "http://www.iupui.edu/~username/transform.cgi?template_path">

The template_path specifies the location of your template. As an example, assume that your account name on the web server is www-user, and the template is stored in your www directory along with the rest of your HTML files. If your template were called comment.tpl, the path you would specify is www-user/www/comment.

This is a combination of your web server account name, the path to your template directory (in this case, www), and the name of the template with no extension. Note the question mark (?) separating the location of Transform and your template path. The question mark is required.

In this example, the complete action= specification would be one of the following:

  http://www.indiana.edu/~username/transform.cgi?www-user/www/comment
  http://www.iupui.edu/~username/transform.cgi?www-user/www/comment

Note that http://www.indiana.edu/~username/transform.cgi or http://www.iupui.edu/~username/transform.cgi is a complete URL to the copy of Transform. You may also provide a shortened URL that is like a normal relative URL: /~username/transform.cgi. Be sure to include the leading slash (/).

Note:

The specification for action = must be on a single line (i.e., with no returns). If you include a return in the action = string, some versions of Netscape may display a "Broken Pipe" message or some other odd message; alternatively, Transform may display the following error with no path given:

  Account does not exist
  Error in path specified:

Virtual host users

To use Transform with a virtual host, you must install Transform in your account as described above. When pointing to Transform in the action = statement, supply the following:

  http://my_virtual_host.indiana.edu/transform.cgi

This assumes you have transform.cgi installed in your standard document directory. If you have it installed in a subdirectory, you must supply additional path information.

Details of creating a template file

Dividing your template into sections

In the examples above, the *email-response* template section header declared that the template information that followed would be sent as an email message. The *success-response* section header declared the section of the template to be displayed to a user who successfully submits the form. There are actually five possible template sections (and section headers) that control how you want to dispense submitted form information. When you create a template file, you simply include the sections you need for your specific application.

When using section headers, you must include one or more asterisks on both sides of the name (e.g., *email-response*, ***email-response***, etc.), and you must always begin them in the first column of your template file.

Important:
Be very careful that you spell the section headers exactly as shown below. If you misspell a section header, Transform may not recognize it as a header and an entire section may be included as part of the previous section.

The five types of sections and their section headers in a template are:

  • *success-response*: Describes the message that is returned to users when they successfully submit a form. Always use this section to inform users that a form was successfully submitted. Because this section is returned to a user's web browser, it must be in the form of an HTML document.
  • *error-response*: Describes the message that is returned to users if they did not fill out the form correctly. As you'll see below, you may specify that certain form variables are required; that is, if the user does not fill them in, the *error-response* section of the template (and only this section) will display.

    By using the !force-error-if command, you can force only the *error-response* to display based on testing the values of the form variables entered by the user. Always use this section if you define required fields or force an error so that you can inform users where they made an error in the form. Because this section is returned to the user's web browser, it must be in the form of an HTML document.

  • *email-response*: Describes the format of an email message to be sent to you. Only use this section if you wish to receive the results of a submitted form as an email message.
  • *append-response*: Describes how you would like form information appended to a data file in your account. Only use this section if you need to have form information appended to a file.
  • *define-variables*: Defines whether a variable is required, error messages for required variables, and the values of some special variables. Like the other sections, this is not required unless you need its special features.

Which sections are used and when

When Transform reads the values submitted via a form, it sets a flag indicating success or error. Transform sets an error flag if a user doesn't complete a required form variable, or if you force an error based on the values the user supplied. If the error flag is set, only the *error-response* section of the template is processed, and no other sections are examined. If there is no error condition, any *error-response* section is ignored; the *success-response*, *email-response*, and *append-response* sections are processed instead.

Setting required variables

If you don't wish to receive the results of a form unless the user fills in a particular field, you can designate that field as required.

In the Transform template file, specify a required field (i.e., variable) by appending req- to the variable name. For example, if you had a text input area named "email" in your form (name = "email"), then in your template, you would normally enclose the email variable in square brackets ([email]). In the template, you can make [email] a required variable by prefixing req- to the variable name ([req-email]).

Note:
Flagging a variable as required with req- doesn't change the name of the variable; the req- is stripped from the variable name as the form is processed.

An example with required variables (using error and response sections)

In the following example, the "email" and "question" fields are required; however, the "name" field is not:

  # begin template file
  # Lines beginning with a # sign are considered comments.
  # Use the *define-variables* section to specify which variables
  # are required. Supply a specific error message for the [email] variable
  *define-variables*
  [req-name]
  [req-email] = "<b> Please enter an email address </b>"
  [req-question]
 
  # The *email-response* line below specifies that this is the email-response
  # section of the template file. Other sections will be described later.
  # The other lines are just plain text with html form variable names
  # enclosed in [ ] where you want the values entered by the user
  # printed in the email message
  *email-response*
  To:smith@indiana.edu
  From:[email]
  Subject: Question from [name]
  Question from [name]
  Supplied email address is [email]
  See the question below:
  [question]
  # Now begin the *success-response* section that will be displayed to
  # the user. Because this is being sent back to the user's browser
  # it must be in the form of a html document
  *success-response*
  <html>
  <head>
  <title>Thank You</title>
  </head>
  <body>
  <h1>Thank You</h1>
  Your name is: [name]
  <br>
  You supplied the following email address: [email]
  <br>
  Your question was:
  <br>
  [question]
  </body>
  </html>
 
  # Now let's add a error-response section
  # Again, this must be in the form of a html document because it is being
  # returned to the user's browser.
  # Remember, this section is displayed to the user when required
  # fields, flagged with req-, are not completed by the user.
  *error-response*
  <html>
  <head>
  <title>Sorry, you made an error</title>
  </head>
  <body>
  <h2>Sorry, you made an error</h2>
  <p>
  You must complete the following fields:
  <p>
  Your name: [name]
  <p>
  Your email address: [email]<p>
  Your question: <br>
  [question]<p>
  Use the <b>back</b>
  selection on your browser to go back and complete
  all required fields.<p>
  </body>
  </html>
 
  # end template file

Try submitting the form with all fields completed, and then submit the form again without completing all fields. Note that when required fields ("question" or "email") aren't filled in, the *error-response* section of the template is returned to you. When all fields are completed, the *success-response* section is returned.

In the above template example, req- prefixed a variable ([email]) only once. If a variable is prefixed with req- anywhere in a template, it affects the variable everywhere else it appears in the template.

Template section details

*success-response* section

The *success-response* section allows you to create a message that is returned to users who successfully submit a form. Always use this section to inform users that their information was successfully submitted. If no *success-response* section is present, the *email-response* or *append-response* section will display to the user instead.

Because the *success-response* is returned to the user's web browser, it must be in the form of an HTML document. For example:

  # This section must be a correct html document
  *success-response*
  <html>
  <head>
  <title>Your title</title>
  </head>
  <body>
  Your html success response with variables included
  in [ ]s anywhere you like. Note that because this
  is an html document, you can include href links to
  other documents or images if you like.
  </body>
  </html>

Since the *success-response* section is an HTML document, you may include HTML forms that call other Transform templates. Using this technique, you can effectively chain multiple forms together.

*error-response* section

The *error-response* section allows you to display an error message to users if there were errors in the submitted form. The only time the *error-response* section displays is if a user didn't fill in a field you specified as required, or if you used the !force-error-if command (see below) to define an error condition based on the user-supplied values. If you have required fields in your template, you should always add an *error-response* section.

Note:
A user who fails to complete a required field can only return to the partially completed form by using the browser's Back button. You may want to indicate this in your *error-response* section.

The format of the *error-response* section, like the *success-response* section, must be in the form of an HTML document because it is returned to the user's web browser. Error messages for form variables that the user doesn't complete will not automatically appear in the *error-response* section when it is returned to the user. To display an error message, you must supply the variable name in brackets ([]). For example:

  # This section must be a correct html document
  *error-response*
  <html>
  <head>
  <title>Your title</title>
  </head>
  <body>
  # Include in your error response variables 
  # in [ ]s anywhere you like. Typically you may want
  # to include something like the following to be sure that
  # the user sees the error message for each variable:
  The following variables must be completed in this form:<p>
  Description of your first variable:[var1]<br>
  Description of your second variable:[var2]<br>
  Description of your third variable:[var3]<br>
  # Here, [var1] would be replaced with the error message
  # for var1 if it wasn't filled in by the user. The same
  # for [var2] and [var3].
  # Also include instructions for getting back to the
  # partially completed form such as:
  Use the <b>back</b>
  selection on your browser to go back and complete
  all required fields.<p>
 
  </body>
  </html>

You can use !print-if to print only the information about the required variables that were missing. For more, see Selecting which lines in any one section are printed.

*email-response* section

The *email-response* section defines the format of an email message that will be sent to you. The first four lines of the *email-response* section must be:

  *email-response*
  To:username_to_receive_message@indiana.edu
  From:some_user@somewhere
  Subject: a subject for the message

General rules for the *email-response* section:

  • There must be no blank lines separating the first four lines shown above. If the three lines following the *email-response* section marker do not contain To:, From:, and Subject: (in exactly that order), Transform won't send the email message.
  • The "To:" field must not be blank.
  • What you have in the body of the message after the first four lines is up to you. You should include one blank line after the "To:", "From:", and "Subject:" header information. Since this will be sent as a normal ASCII mail message, any blank lines or spaces you include in the body of the *email-response* section will appear in the email message.
  • If you do not define a *success-response* or *error-response* section in your template file, the *email-response* section will be used in their place to send a response back to the user after the form is submitted. This is bad practice; you should always supply the other sections.
  • A note on building a "From:" address: For publicly available forms, you should request the user's email address and have the variable inserted into the "From:" field (e.g., From:[email]). Remember, however, that this cannot be trusted. The user could enter anyone's email address.
  • When using the iu_auth or iupui_auth form of Transform, you can build the "From:" email address with an environment variable. The !NETWORK_ID variable is set to the user's network username. By adding @indiana.edu or @iupui.edu to the !NETWORK_ID, you can build a trustworthy "From:" address (e.g., From:[!NETWORK_ID]@indiana.edu or From:[!NETWORK_ID]@iupui.edu). For more about iu_auth or iupui_auth and other ways of restricting access, see Authentication: Controlling access to your forms and documents.

*append-response* section

The *append-response* section defines how form information will be appended to a data file. The format of the *append-response* section is up to you; like the other template sections, you include a form variable name in square brackets to have its value included in the file.

Important:
Do not use the semicolon (;) or ampersand (&) characters as field delimiters in your append file.

Use the *append-response* section any time you want the submitted form information appended to a file. Examples might include collecting data to be added to a database or having form information appended to an HTML file to be displayed to users (e.g., for a guestbook).

You can modify how or when information is appended to a file with a variety of commands (described below). All the commands begin with an exclamation point (e.g., !command), and must immediately follow the *append-response* section header, one command per line. They must also begin in column 1. The first line following the *append-response* header that does not begin with one of the following commands is treated as the beginning of the information you want appended to a file.

The Transform commands specific to the *append-response* section include:

  • !append-file-name = your_file_name
  • !append-after = "string"
  • !append-before = "string"
  • !record_delimiter
  • !append-mode = overwrite

These will be discussed after a short example.

Example

Assume you have a form which collects information for three form variables, [name], [email-address], and [comment], and you want the results of a form submission appended to a file. You could use the following *append-response* section:

  *append-response*
  !append-file-name = my_file_name
  Name:          [name]
  Email address: [email-address]
  Comment :      [comment]

In the above example, the information would append to a file just as you see it, except the values entered by the user submitting the form would replace the variable names in square brackets.

Specifying where the data is appended (!append-file-name)

The default: If you don't specify an !append-file-name command, Transform will attempt to build a default file name. This isn't a good idea, but it is allowed. By default, the results of the form are appended to a file called service.dat (where service is the name of your form/template without the extension) in a directory called form_data in your login directory. To use this default behavior, you must first create a directory called form_data in your login directory. If the service.dat file does not exist, it will be created (and then appended to next time).

Using the !append-file-name command

You must place the !append-file-name command immediately following the *append-response* section header along with other !commands. The general form of the !append-file-name command is:

  !append-file-name = "file_to_append_to"

Replace file_to_append_to with the path to a file.

There are three possible ways to specify the "file_to_append_to":

  1. A complete path. If you type pwd (meaning "print working directory") in any directory, you will see a complete path to that directory. To create an acceptable "file_to_append_to", add the specific append file name to the result of the pwd command. For example: /ip/account/my_append_directory/my_append_file_name.dat.
  2. A path relative to your login directory. If the "file_to_append_to" begins with a tilde (~), it is assumed that the path is relative to your login directory. For example: ~account/my_append_directory/my_append_file_name.dat.
  3. A simple file name. If "file_to_append_to" is just a file name with no slashes (/) indicating the path, Transform will append to the "file_to_append_to" in your default append directory, form_data. For example, the command !append-file-name = "mydata.dat" would append the form data to the mydata.dat file in the form_data directory, which is in your login directory. (As described above, you must create the form_data directory before appending to files there.)

General rules for !append-file-name

  • If the "file_to_append_to" specified does not exist, Transform will create it.
  • You must create the directories first. If you specify a complete path to a file and the directories in the path do not exist, Transform will report an error and won't create the directories.
  • You may only append to files in your own account.

Illegal characters: When naming an append file (and any directories that lead to them), you may only use the following characters: A-Z, a-z, 0-9, hyphen (-), underscore (_), and period (.). In addition, tilde (~) and slash (/) may be used when supplying paths to these files.

Be aware that in the !append-file-name = "file_to_append_to" command, the "file_to_append_to" may include one or more form variable names in brackets. Before appending to the file, the "file_to_append_to" string will have any variable name in brackets replaced by their value. This allows you to change the name of the append file based on user form input. For example, if you had a form variable named class that had possible values of freshman, sophomore, junior, or senior, you could write data to freshman.dat or sophomore.dat, etc. using the following:

  !append-file-name = "~account/my_dir/[class].dat"

[class] would be replaced with the value for the class variable in the append file name. Note, however, the warning about illegal characters above. If you attempt to create a file name based on variables supplied in a text input area by the user, an error may result if the user enters illegal characters. (For more, see the !trim section.)

Protecting append files

When creating or modifying an append file, Transform makes the following assumptions about how the file should be protected (e.g., readable by others or not):

  • If the append file is being created in your web directory where normal HTML files go (i.e., www or wwws), Transform assumes that you want the append file delivered over the web (e.g., a guestbook) and creates the file with world-read privileges.
  • If the file is being created anywhere outside the web directory, Transform assumes that the file should remain private and creates it such that only the owner has privileges.
  • If Transform is appending to a file that already exists (that you or Transform created), it will not change the privileges. If you change the privileges of a file, Transform will honor these changes.

Controlling where your data is appended in a file (!append-after and !append-before)

Two commands, !append-after and !append-before, give you some control over where new information is placed in an append file. The general form of these commands is:

  !append-after = "string"
  !append-before = "string"

In the above example, string is some string in your append file. If you supply one of these commands, Transform will search your append file for the first occurrence of string, and then place the new form data on the line immediately before (if you used !append-before) or after (if you used !append-after) this string.

You may only use one of these commands in any given *append-response* section.

As an example, let's assume you have an HTML guestbook file with a standard header and footer, and you want Transform to place any new information submitted in a form between the header and footer. You could do this by placing an HTML comment such as <!-- include after here --> between the header and the footer at the beginning of an *append-response* section. For example:

  *append-response* 
  !append-after = "<!-- include after here-->" 
  ... the rest of your append response goes here ...

This would cause all new submissions to append immediately after the <!-- include after here --> HTML comment. Note that this would also prepend the newest submissions to the top of the file (right after the comment but before previous submissions). If you used !append-before instead, the newest submissions would be at the bottom of the file, before the comment, but after previous submissions.

If Transform doesn't find the string for an !append-before or !append-after command, Transform will append the new information to the end of the file (and no warning message will display).

Warning:
You must be very careful about the size of your files if you use !append-before or !append-after commands. To insert information at the appropriate place in the file, Transform must read through the entire file and then re-write it. Appending in this fashion can become very slow if the file grows large. Avoid using these commands if you are simply collecting data and the files may become large.

As described for the file name in the !append-file-name command, the string following !append-before or !append-after may contain form variable names in brackets. This allows you to have multiple comment tags in an HTML document, with information being placed before or after a particular tag based on the value of a form variable supplied by the user.

Including record delimiters in your files (!record-delimiter)

Important:
Do not use the semicolon (;) or ampersand (&) characters in your append file as field delimiters.

When using append files to collect information, it is often useful to have begin and end record markers included in the file so you know where one submission ends and the next one begins. You can do this by including tags in your *append-response* section which mark the beginning and end of the record, or you can allow Transform to do it for you.

If you include !record-delimiter at the beginning of the *append-response* section (along with any other !commands), Transform will automatically include the following HTML comments at the end of each submitted record:

  <!-- Begin Record "seconds" "date" -->
  at the beginning of each submitted record and
  <!-- End Record -->

Here, "seconds" is the number of seconds since January 1, 1970 (useful for easily determining the age of a record), and "date" is the current date (e.g., Mon Jul 6 13:43:16 EDT 2015).

Transform writes the begin record comment this way because another application, which is not yet complete, will allow you to scan your append file containing this standard begin record tag and eliminate records older than some number of hours or days. For example, cleaning up older records might be important for a ride board, calendar, or other application where old records should be removed or archived.

You may also have additional information in the begin record comment tag by including a string after the !record-delimiter command, where string is any string (and may include form variables in brackets):

  !record-delimiter = "string"

This writes string in the begin record tag after the date and before the close of the HTML comment.

Appending to or overwriting files (!append-mode = overwrite)

Normally, Transform just appends (or adds) data to a file (although you can control where it includes new information with !append-after and !append-before). However, there are occasions where you'd want Transform to completely overwrite a file with the new form information. You can enable this with the !append-mode = overwrite command.

If you place !append-mode = overwrite at the beginning of your *append-response*, new information will overwrite rather than append to the file specified with the !append-file-name command. Be aware that this destroys any old information in the append file.

As an example of when you might wish to do this, assume that you want to create an HTML file that contains the date when your form was last used. The following *append-response* section would create a new (overwritten) file that includes the current date every time your form is submitted to Transform (this uses the [!DATE] environment variable to stamp the date in the file).

  *append-response*
  !append-file-name = ~account/www/last_date.html
  !append-mode = overwrite
  # Remember lines beginning with # are comments
  # The first line following the *append-response* header
  # that doesn't begin with ! is the beginning of the data for the file
  <html>
  <body>
  This form was last accessed on [!DATE]
  <p>
  </body>
  </html>

Editing, copying, or moving your append files (tf_lock and tf_unlock)

If you attempt to edit an append file while Transform is trying to append new user-supplied information to it, you may get unexpected results. Before Transform adds information to your append file, it first creates a lock file. If you need to edit an append file, you must let Transform know you are in the process of modifying the file. You do this with two utilities, tf_lock and tf_unlock:

  1. Log into your account and cd to the directory containing the append file you wish to edit.
  2. To create a lock file, type tf_lock file_name, where file_name is the name of the append file you wish to modify.
  3. Edit your file. Since it is locked, Transform will postpone any modification to the file until it is unlocked.
  4. Type tf_unlock file_name to unlock the file (don't forget, or no new information will be appended).

In general, use tf_lock and tf_unlock any time you need to work with append files and don't want Transform simultaneously trying an append operation.

Transform appends to files immediately when the form is submitted. The only exception is when you lock the file with tf_lock. If a user attempts to append to one of your files while you have it locked, Transform will temporarily store the user append information in your account. Once you unlock the file, the next form submission to your account will cause any pending user information to be appended in the order in which the information was received.

*define variables* section

The *define-variables* section, unlike the other template sections, is never output. It sets the properties of various global variables, sets global error conditions, and defines properties for required variables. A discussion of each feature follows.

Setting required variables

As shown in the examples above, a variable name that begins with req- anywhere in the template file is considered a required variable or field. Often, especially in forms with lots of variables, it isn't convenient to have your req- declarations sprinkled all over the template file. To avoid this, use the *define-variables* section to define all your required variables in a single compact section, typically at the top of your template file.

Each variable name listed in square brackets in the *define-variables* section must be on a line by itself. For example:

  # Begin the define-variables section
  # Remember lines beginning with # are comments
  # This sample section simply declares that the
  # following three variables are required
  *define-variables*
  [req-name]
  [req-email]
  [req-question]
  #end define-variables section
  # other sections follow
  ... include other sections here ...
  #end template

Specifying error messages for required variables

By default, when a user fails to fill out a required variable, Transform will replace the empty value of the variable with the following:

  **** Error - value required *****

When the *error-response* section of your template displays to the user, this error message will be printed where the variable name in square brackets appears (just as an actual user-supplied value would). Think of this error message as the default value for all required variables; if the user doesn't supply a value, the error message will display.

In the *define-variables* section, you can override this default and specify an error message for each required variable by using the following format:

 [req-yourvariable] = "Your error message for this variable"

Since this error message is returned to the user via the *error-response* section, it is effectively part of an HTML document. Thus, you may include HTML markup tags in your error message. This includes not only simple markup like bolding your error message (e.g., <b>Error Message</b>), but also links (i.e., <a href= ...) to other documents that might describe how to complete the form field.

Because your error message may be long (especially if you include links to other documents), it may continue on multiple lines. Remember to start each new required variable name (in square brackets) on a new line. Also, you may include variable names in square brackets (e.g., [req-email] = "Sorry [name], email address required") in the body of the error message. For example:

  # begin define-variables section 
  # quotation marks around the error message are optional 
  *define-variables* 
  [req-name] = <b>You must complete the name field</b> 
  [req-email] = "The email field is required, see 
  <a href="http://www.indiana.edu/~www-user/email_instruct.html">
  Email Instructions</a> for information on 
  completing the email address field" 
  # Since no error message is supplied for [req-question]
  # below, the default error message will be used 
  [req-question] 
  # end define-variables section

Special command variables in the *define-variables* section

You can also change some of Transform's default behavior by including special command variables and their new values in the *define variables* section. These are of the general form:

  !special_variable_name = new value

Each special variable name begins with an exclamation point (!). Each !special_variable = new value must begin on a new line, and most may continue on multiple lines if necessary. You may use the following special command variables in your *define-variables* section:

  • !general-error-message = "your default error message"

    The !general-error-message command allows you to change the default error message. By default, when the user doesn't complete a required field, Transform inserts **** Error - value required ****.

    While you can provide an individual error message for each required variable (see above), you may also change this default error message by including general-error-message = "your default error message".

    Note that HTML codes may be included in the !general-error-message, including links to other documents if appropriate.

  • !append-file-name = file_to_append_to

    The !append-file-name command allows you to set the name of the file you want the form information appended to. You should place this command at the top of your *append-response* section. For more, see Specifying the filename where data is appended.

  • !show-sig = no

    By default, the Transform signature, "<hr/> Form processed by Transform version #.#", will appear at the end of the page returned to users. To remove this signature from your response, include the line !show-sig = no in the *define-variables* section of your template file.

  • !checkbox-html-delimiter = "delimiter" and !checkbox-text-delimiter = "delimiter"

    These two command variables are similar and will be discussed together. If you don't use HTML checkbox-type input fields, skip this section.

    The HTML forms language allows you to create multiple checkboxes which have the same NAME = variable_name (if you don't use the same NAME= for multiple checkboxes, skip this section), resulting in multiple values for the same variable name. The problem, then, is how to display multiple values for the same variable name. Transform does this by inserting a delimiter between each value for the variable when they display as the result of a [checkbox-variable] in your template. By default, Transform puts a comma followed by a space (, ) between the values.

    The two command variables, !checkbox-html-delimiter and !checkbox-text-delimiter, allow you to change this default delimiter.

    The !checkbox-html-delimiter command variable changes the delimiter when a checkbox value is displayed in the *error-response* and *success-response* sections of your template (remember, these sections are HTML documents). For example, !checkbox-html-delimiter = "<br>" would result in a line break between each checkbox value when the *error-response* or *success-response* is returned.

    The !checkbox-text-delimiter command variable changes the delimiter used in the *email-response* and *append-response* sections of your template (remember, these are plain text documents). For example, !checkbox-text-delimiter = " - " would result in a space, a dash, and a space between each checkbox value in the *email-response* and *append-response* sections.

  • !trim = [var1] [var2] [var...]

    Use the !trim command if you want to ensure variables supplied by the user have no leading or trailing spaces. Any variable names in square brackets after the !trim = command will have any leading or trailing spaces removed. The !trim command may not be continued on multiple lines, but you may repeat it as many times as you like. This command can be handy if, for example, you want to build a file name with a word supplied by the user in a text input area and want to ensure it has no leading or trailing spaces.

  • !force-error-if expression

    The !force-error-if command lets you force the use of the *error-response* section (and as a result, no other sections) based on the values of the variables supplied by the user. For more, see Forcing use of the *error-response*.

  • !use-linebreak mode = [var1] [var2] [var...] and !linebreak-delimiter = "delimiter"

    There may be a problem when you use <textarea> input areas in your forms. Users may type or paste multiple paragraphs into these textarea boxes. If this text (via a Transform variable) then displays as an HTML document (e.g., *success-response*, *error-response*, or an append file that is an HTML document), any white space separating paragraphs will be represented as a single space in the HTML document, and thus paragraphs will run together. This is typical for HTML documents; <br> and <p> tags are generally used to achieve line breaks and paragraphs.

    The Transform !use-linebreak-mode command can help alleviate (but not eliminate) this problem. The !use-linebreak-mode command tells Transform which of your form variables are textareas. When outputting these variables to HTML documents, Transform will add an HTML line break (<br>) before each hard return. The assumption is that word processors place a hard return at the end of paragraphs, and if a user is typing into a textarea box, they will use the Enter key to indicate paragraph or line breaks. Thus, if a user pastes text into a textarea from a word processor document or simply types into the textarea, the <br> added before the hard return will simulate, via HTML markup, the line breaks intended by the user.

    You can include the !use-linebreak-mode command either in the *define-variables* section or at the beginning of any other section (along with any other !commands). It has the general form:

      !use-linebreak-mode = [var1] [var2] [var...]

    In the above example, [var1], [var2], and [var...] are the textarea variables in your form you'd like treated this way.

    Unlike many other *define-variables* commands, the !use-linebreak-mode command cannot be continued on multiple lines. If you have more [variables] than will fit on a single line, repeat the !use-linebreak-mode command as many times as necessary to list all your variables. Note that the addition of the HTML line break, <br>, is typically useful only if the template section will result in HTML output (e.g., you wouldn't want many <br> tags in your email messages). Transform makes the following assumptions about which sections are to be treated as HTML documents and therefore when it will include <br> tags before hard returns:

    Transform will always honor !use-linebreak-mode commands at the beginning of a *success-response*, *error-response*, *append-response*, or *email-response* section. Transform will ignore any !use-linebreak-mode commands in *define-variables* while that section is being processed (i.e., !use-linebreak-mode commands for individual sections override settings in the *define-variables* section).

    Given the above, if you include !use-linebreak-mode commands in the *define-variables* section, the following rules apply:

    Since Transform always returns *success-response* and *error-response* sections to the user's browser as HTML documents, Transform always performs this conversion on specified variables in these sections.

    Transform will perform this conversion on *append-response* sections if the append file name ends in .html; it assumes that you want an .html append file viewed via the web. If the append file name ends in anything other than .html (i.e., you're using the *append-response* section to collect data), Transform won't perform this conversion.

    Transform never performs this conversion on *email-response* sections, since these are mailed as plain text documents.

    As described above, !use-linebreak-mode places a <br> before any hard return. If you enclose a textarea variable that is being processed by the !use-linebreak-mode command in <pre> and </pre> tags, the resulting lines will be double spaced. This is because both the <br> and the hard return cause a line break. To avoid double spacing, change the line break character to <br> by including the following line in your *define-variables* section:

      !linebreak-delimiter = "<br>"

    You may get unexpected results if you set the line break delimiter to anything else.

Handling illegal/reserved template characters ([, ], and |)

Three characters cause problems if you try to use them as normal printing characters in your templates: [, ], and |. You can only use square brackets ([ and ] ) in your templates on either side of a variable name. Vertical bars (|) cannot be used as printable characters, because Transform uses them internally.

To print these characters, use character codes in their place. Character codes will convert to the appropriate characters. The character codes are as follows: %5b ([), %5d (]), %7c (|).

Environment variables (!DATE, !HTTP_USER_AGENT, etc.)

In addition to the variables you have defined in your form, you may print some standard environment variables.

Environment variables must begin with an exclamation point (!), and should be uppercase to distinguish them from your own variables. Like other variables, they must be enclosed in square brackets in your template. Environment variables currently allowed include:

  • [!NETWORK_ID] - The user's Network ID when using iu_auth or iupui_auth forms of Transform. This variable is not set unless using iu_auth or iupui_auth, or if you have developed an .htaccess file that requires users to enter a username and password.
  • [!DATE] - Prints the date and time
  • [!HTTP_USER_AGENT] - The type of web browser being used
  • [!REMOTE_HOST] - The name of the machine making the form request
  • [!REMOTE_ADDR] - The IP number of the machine making the form request
  • [!TIME] - The number of seconds since January 1, 1970. This is useful for creating unique filenames. For example, !append-file-name = "[!TIME].html" would create unique file name each time someone uses the form and template.

While the [!DATE] variable above allows you to stamp the current date, it prints a complete date string. If you wish to customize the date format, use the following additional environment variables:

  • [!SDOW] - The day of the week abbreviated to three characters
  • [!DOW] - The day of the week (complete spelling)
  • [!SMOY] - The month of the year abbreviated to three characters
  • [!MOY] - The complete month of the year
  • [!D] - The day of the month (1 or 2 digits as required)
  • [!DD] - The day of the month (always 2 digits; e.g., 01, 02)
  • [!M] - The numeric month of the year (1 or 2 digits as required)
  • [!MM] - The month of the year (always 2 digits)
  • [!YY] - The year (2 digits)
  • [!YYYY] - The year (4 digits)
  • [!HOUR] - The hour of the day (always 2 digits)
  • [!MIN] - The minute of the hour (2 digits)
  • [!SEC] - The seconds (2 digits)

Debugging your templates (!debug)

By default, Transform tries to inform you of errors in your templates. There are cases, however, when Transform can't be sure whether a line contains an error or something you intended, and as a result reports nothing. This can lead to unexpected results when running Transform.

To assist with this problem, you can tell Transform to use debug mode while scanning your templates. In debug mode, Transform will more carefully examine each line and report potential errors.

To invoke debug mode, include !debug as the first line in your template. If you add a 2 to this line (i.e., !debug 2), in addition to potential errors, Transform will report information about the variables and sections it finds in your form and template. This can be useful for detecting misspellings of variable names and section headers.

Be sure to remove (or comment out with a #) the !debug command before putting your form/template in production; this mode always results in the printing of beginning and ending debug headers.

Advanced use

Transform has additional features that allow chaining forms together and conditional display of information based on user input. The following assumes that you understand the general form/template features described above.

Using multiple sections

Transform allows you to have only one *define-variables* section, but you may have as many different *success-response*, *error-response*, *email-response*, or *append-response* sections as you like in any template.

For example, your template might contain two *email-response* sections if you wanted to send two differently formatted email messages (e.g., a user confirmation message and an internally formatted message with different information). As another example, you might want to use two *append-response* sections to append different information to two different files.

Transform examines and processes multiple sections of the same type (e.g., multiple *success-response* sections) in the order they appear in your template. When using multiple sections, keep the following in mind:

  • If you have multiple *success-response* sections that qualify to be output (see Conditional branching), they will be output in the order they appear in the template (i.e., concatenated together). The same is true for *error-response* sections; however, they display only when a required variable is missing or a !force-error-if error condition is set.
  • If you have multiple *append-response* or *email-response* sections, Transform processes them in the order they appear in the template, but each section is processed independently (i.e., there is no concatenation of multiple sections of the same type).
  • Internally, Transform processes and outputs your sections in the following order: any *error-response* sections (if required, and then stops), any *email-response* sections, any *append-response* sections, and finally, any *success-response* sections. In addition, Transform performs some error checking just before each section is output. As a result, if when first developing a Transform template you make errors, Transform may process and output the sections without errors if they appear first in the template. Transform will then stop when it reaches the error.

Conditional branching (!use-if)

Transform supports a form of conditional branching. This feature allows you to control which sections in your template are processed based on the form values supplied by the user. The general idea is that you may begin a template section with a !use-if command which defines a logical test against the value of one or more form variables. The entire section will only be processed if the expression is true. The general form of the !use-if command is:

  !use-if expression

In the above example, expression is a logical expression. The expression may be as simple as testing the value of a single variable (e.g., !use-if [food] eq "apple") or, as in the following example, a more complex test of multiple variables.

Assume you have an HTML checkbox on your form that allows users to indicate that they would like to receive a confirmation email message after submitting a form. The HTML code for this checkbox might look like:

  Check this box to have a confirmation email message sent
  <input type = checkbox name = confirm value = yes>

The name of this checkbox is confirm; if checked by the user, it would send a value of yes to be processed.

You could then create an *email-response* section in the corresponding template file that would only be sent if this checkbox were checked by including a conditional test:

  *email-response*
  !use-if [confirm] eq "yes"
  To:whoever@indiana.edu
  From:[username]@indiana.edu
  Subject: Confirmation message
  ...the rest of your message template...

In the conditional test above, !use-if [confirm] eq "yes" says process this section (in this case, send an email message) if the HTML form variable confirm has a value of yes.

Note that the conditional test immediately follows the *email-response* section header. Transform ignores conditional test statements if they do not immediately follow the section header.

General rules for !use-if

  • The !use-if command is allowed in the *success-response*, *error-response*, *email-response*, or *append-response* sections and must immediately follow the section header, before any other !commands you may need for that section. They are not allowed in the *define-variables* section, which is never output to users.
  • Each section may only contain one !use-if command.
  • The !use-if command must start in column 1. Expressions may span multiple lines, but each continuation line must begin with !! starting in column 1.

General rules for building expressions

Following are general rules for building logical expressions. While these are shown with the !use-if command, the expressions can also be used to control which lines of a section are printed (!print-if) or to set an error condition (!force-error-if).

Allowed comparison operators

Following is a complete list of available c operators:

Comparison operator Meaning
eq equal string comparison q
ne not equal string comparison
== equal numeric comparison
!= not equal numeric comparison
> numeric greater than
< numeric less than
<= numeric less than or equal
>= numeric greater than or equal
=~
Perl regular expression matches
!~
Perl regular expression doesn't match

In addition, you can use the following shortened test (i.e., without an operator or value) to see if the variable has any value (that is, if anything was entered by the user). Simply enter the variable name without an operator. For example, !use-if [var] would be true if [var] has any value other than null ("") or zero (0).

Note the difference between string and numeric comparisons. For example, a string comparison of 1.0 e 1 would be false because strings are being compared, but 1.0 == 1 would be true because numerically, 1.0 equals 1. Be sure to use the correct comparison type. In addition, note that string comparisons are case insensitive, e.g., YES eq yes would be true.

For more about the =~ and !~ Perl regular expression operators, see Using Perl regular expressions in conditional tests.

Allowed Boolean operators

In addition to the comparison operators above, you may use the following Boolean operators when building tests for multiple variables:

Boolean operator Meaning
not logical not
and logical and
or logical or

You can use these operators to test the values of multiple variables in a single test. Boolean operators are evaluated in a specific order: "not" is evaluated first, followed by "and", and finally "or". If needed, you can also use parentheses to group tests together and ensure the evaluations are in the order you intend. If the test you wish to use won't fit on one line, you may use multiple lines. Any additional continuation lines must, however, begin with !! in column 1. For example:

  !use-if [class] eq "freshman" or [class] eq "sophomore"
  !use-if [class] eq "freshman" or [class] eq "sophomore"
  !! or [class] eq "junior"
  !use-if ( [class] eq "freshman" or [class] eq "sophomore" )
  !! and [school] eq "business"

Multiple comparisons (!use-if examples)

Often you may want to test the values of two or more variables to determine whether a given section should be used; for example:

  • The following two lines would cause a section to be processed if the form variable computer had a value of "ibm" and the form variable problem had a value of "printing":
      !use-if  [computer] eq "ibm" and
      !!       [problem]  eq "printing"
  • The following two lines would cause a section to be processed if the form variable location had a value of "IU" or the form variable host had a value of "IU":
      !use-if [location] eq "IU" or
      !!      [host]  eq "IU"
  • Things become more complicated when you need to use multiple logical operators together. For example, assume that you want to process a template section only if favorite-color is "red" and class is either "grad" or "senior" (i.e., process the template section for either graduate students or seniors whose favorite color is red). Consider the wrong and right ways to do this:

    Wrong:

      !use-if [favorite-color] eq "red" and
      !!      [class] eq "grad"   or   [class] eq "senior"

    Remember, "and" statements are evaluated before "or" statements. This !use-if command says process this section only if users' favorite color is red and they are "grad" students; then, add (or) all seniors, so the combined set ends up being true for grads whose favorite color is red plus seniors.

    Right:

      !use-if [favorite-color] eq "red" and
      !!      ( [class] eq "grad"   or   [class] eq "senior" )

    By putting parentheses around the "or" tests for [class], you ensure that these tests are evaluated first (so [class] must be "grad" or "senior"). They are then evaluated in an "and" statement with [favorite-color]. Thus, given all grads and seniors, pick those whose favorite color is red.

Forcing use of the *error-response* (!force-error-if)

!force-error-if expression

Normally, the *error-response* section of your template displays to the user only if the user didn't complete a required variable; if the *error-response* displays, other sections are not processed (no *email-response*, *append-response*, etc.). However, you may want to test the values of variables (e.g., eq, ne, etc.), and then create an error condition if the user entered an incorrect value. That is, an inappropriate value for a variable is an error in the same way that a missing required variable is an error. The !force-error-if command allows you to do this.

The general form of this command is !force-error-if expression, where expression is any legal conditional expression. For example:

  !force-error-if [answer] > 10

The above would cause an *error-response* (and no other sections) to display if the value of the variable [answer] were greater than 10.

For more about building conditional tests, see General rules for building expressions. (The syntax for !force-error-if is exactly like that described for !use-if.)

Using !force-error-if

  • !force-error-if commands must appear in the *define-variables* section of your template; a !force-error-if declaration is a global condition that is not specific to any particular section.
  • You may include as many !force-error-if commands as you like. If any one of them is true, Transform sets an error condition and an *error-response* displays.
  • As described for !use-if above, expressions may continue on multiple lines. Continuation lines must start in column 1 and begin with !!. For example:
      !force-error-if  [please_register] eq "yes"
      !!          and  [class_time] eq ""

    If a !force-error-if condition is true, Transform sets an error condition and some *error-response* displays. You may have multiple *error-response* sections with !use-if commands at the top that resolve which *error-response* should display. The !force-error-if command only sets the error condition; it doesn't specify which *error-response* should display. Consider the following template:

      # begin template
      *define-variables*
      !force-error-if [user-type] eq "student"
      !!     and  [class-level] eq ""
      !force-error-if  [please_register] eq "yes"
      !!          and  [class_time] eq ""
      *success-response*
      ... whatever ...
      *error-response*
      !use-if [user-type] eq "student"
      !!     and  [class-level] eq ""
      ...
      Hey, you say you're a student.
      Please go back and specify freshman, sophomore, junior
      or senior.
      ...
      *error-response*
      !use-if  [please_register] eq "yes"
      !!          and  [class_time] eq ""
      ...
      If you'd like to register, please go back
      a select a time for the class.
      ...
      # end template

    In this example, a different *error-response* will display depending on which !force-error-if condition is true. If both error conditions are true, Transform would display both *error-response* sections because both are valid based on the conditions tested. For another way to conditionally control what information displays, see !print-if below.

Selecting which lines in any one section are printed (!print-if and !end-print-if)

!print-if

The !use-if conditional branching section above describes how you can control which sections in your template file are processed. However, there are occasions when you'd like to control which lines in any one section are printed. This is what the !print-if command allows you to do. Using this command (along with the closing !end-print-if command), you can have just a subset of the lines in a section printed based on the value of one or more form variables. This command has the general form:

  !print-if expression

  ...
  the lines to print
  ...

  !end-print-if

Using !print-if

  • !print-if commands are allowed anywhere in the *success-response*, *error-response*, *email-response*, or *append-response* sections, except they must follow any other !commands that appear after the section header (e.g., !append-file-name, !use-if, etc). That is, they appear in the body of the section to control which lines are output.
  • Think of !print-if as a way of defining a block of lines to be printed given the value of a form variable. You must indicate the end of each block to Transform. You can end a block with either another !print-if command, or with the terminating !end-print-if command. You must terminate the last !print-if (block) in any one section with a !end-print-if command. A typical application of !print-if might look like:
      # begin section
      *section-header*
      ... beginning lines for this section ...
         
      !print-if [some_var] eq some_value
      ... a block of lines ...
      !print-if [some_other_var] eq some_value
      ... a block of lines ...
      !end-print-if
         
      ... ending lines for this section ...
      # end of section
  • Like !use-if and !force-error-if, the expressions following !print-if may continue on multiple lines. Any continuation lines must begin in column 1 with !!. For example:
      !print-if ( [color] eq "red" or [color] eq "blue" )
      !!  and  [answer] eq "yes"
      ... print lines ...
      !end-print-if
  • Remember that the value of a variable that was not entered by a user will always be equal to "". This is true for conditional test expressions in general, but is particularly handy for !print-if commands.

    Thus, !print-if [var] eq "" will always be true if a variable was not entered; !print-if [var] ne "" will always be true if a variable was entered and has any value; and the shortened test, !print-if [var], will always be true if a variable having any value other than 0 (zero) was entered.

Example

There may be times when you have a lot of form fields that the user is not required to complete, and you'd like to have any blank fields eliminated before receiving that data. The !print-if command allows you to do this. Assume you have a form that collects name ([name]), address ([address]), email address ([email]), class registration information ([registration]), and a comment ([comment]). Further, assume you'd like the results of the form emailed to you, but you also want the comment field eliminated if no comment was entered. You could accomplish this with an *email-response* section like the following:

  *email-response*
  To: user@indiana.edu
  From:[email]
  Subject: Registration Information
 
  # Print out the variables we always want printed
  # (although they may be blank depending on whether they
  # were made required fields)
  Name:[name]
  Address:[address]
  Email address:[email]
  Registration information:[registration]
  # Now print out the comment, but only if it was entered by the user.
  # Use the shortened version of !print-if with no test for a value.
  # This says print the comment if it had any value
  <b>!print-if [comment]</b>
  Comment:[comment]
  # add the required ending statement
  <b>!end-print-if</b>
  # end of *email-response* section

An *error-response* example

Assume you have an *error-response* like the following:

  # There were three form variables: "name", "email" and "question"
  # Recall that "name" and "question" were required variables
  *error-response*
  <html>
  <head>
  <title>Sorry [name], you made an error</title>
  </head>
  <body>
  <h2>Sorry [name], you made an error</h2>
  <p>
  You must complete the following fields:
  <p>
  Your email address: [email]<p>
  Your question: <br>
  [question]<p>
  </body>
  </html>

With this type of *error-response*, all required variables must be printed so the error messages for the missing required variables appear. In the following example, the *error-response* is modified to print only missing required variables:

  *error-response*
  <html>
  <head>
  <title>Sorry [name], you made an error</title>
  </head>
  <body>
  <h2>Sorry [name], you made an error</h2>
  <p>
  You didn't complete the following required fields:
  <p>
  # Remember that variables that weren't entered by the user
  # will always be equal to ""
  # If [email] has no value print the error message for [email]
  !print-if [email] eq ""
  Your email address: [email]<p>
  # If [question] has no value print the error message for [question]
  !print-if [question] eq ""
  Your question: [question]<p>
  # end the block of !print-if commands
  !end-print-if
 
  </body>
  </html>

Using !print-if, !force-error-if, and required variables together

Following is a brief example of how you might use !force-error-if, !print-if, and required variables together to create an effective *error-response* for a form. This example is not complete; it only shows the relevant portions of the template.

Assume you are creating a form that allows users to register for some class section. In this form, the [name] variable is always required. Also assume there is one section on Thursday, but two on Friday. Thus, if a user selects Thursday, no further information is needed. A user who chooses Friday, however, must also indicate the class time; the day of the week is stored in the variable [class_day], and the time of day in [class_time].

This example demonstrates a situation where a variable is conditionally required (i.e., required only if another variable has some specific value):

  *define-variables*
  # Make "name" a plain 'ol required variable
  [req-name]
  # force an error if they selected Friday but didn't enter
  # a class time.
  !force-error-if  [class_day] eq "Friday" and [class_time] eq ""
  *success-response*
  ... some success-response ...
  # Develop an error-response that tests for each possible
  # error condition
  *error-response*
  ... some html header information ...
  # Test to see if if there was an error because [name] wasn't entered
  !print-if [name] eq ""
  Please go back and enter your name. It is required! <p>
  !end-print-if
  # Now check to see if there was an error because they selected Friday,
  # but didn't give a time. This is exactly the same test as used in the
  # force-error-if command above in the *define-variables* section.
  !print-if   [class_day] eq "Friday" and [class_time] eq ""
  Hey, if you want to go on Friday, you must also specify a time.
  Please go back an select a time. <p>
  !end-print-if
  ... end the error-response html ...

Using external files as part of your template

If you create many forms/templates, you may find that there are portions of a template file that you constantly repeat from template to template. Building a template would be easier if you could place these various portions in separate files. You may also find that you would simply like to include other files (or portions of files) as part of your response to users when building your template. Transform has two commands that allow you to include information from external files:

  !include = your_file_name
  !print-file = your_file_name

To understand the difference between these commands, it is useful to know how Transform processes your form/template. Transform begins by assembling your entire template (which may be made of component files brought in via !include). Once Transform has your whole template, it examines the submitted form variables, determines which section types you have included in your template, and begins processing the sections of your template. During this process, it evaluates any conditional elements (e.g., !use-if, !force-error-if, !print-if), and finally outputs the appropriate sections (or lines) of your template and processes any !print-file commands.

While !include and !print-file both allow you to read in files external to your template, they operate at different points in the process and offer different features:

  • !include commands are processed at the initial stage when Transform reads your template. As a result, new sections (via *section-headers*) can be defined in files read in via !include.
  • !print-file commands are processed at the final step when appropriate sections or lines are output.

Building a template from separate files (!include)

!include allows you to include standard template sections that are stored in a separate file. For example, assume that you wanted to include the same HTML *success-response* for multiple forms. If you put the entire *success-response* in a file called success.html, you could include it in any number of templates like so:

  # begin template
  *email-response*
  ... your email response template information...
  *error-response*
  ...any error message...
  # Now simply !include the standard *success-response*
  !include = "success.html"
  # end template

This would insert your success.html file into your template while the template file is being read.

The general form of the !include command is:

  !include = "file_name"

There are three possible ways to specify the "file_name":

  1. A complete path. If you type pwd (meaning "print working directory") in any directory, you will see a complete path to that directory. To create an acceptable "file_name" for !include, you would add the specific include file name to the result of the pwd command. For example:
    /ip/account/some_directory/my_include_file_name.dat
  2. A path relative to your login directory. If the "file_name" begins with a tilde (~), it is assumed that the path is relative to your login directory. For example:
    ~account/some_directory/my_include_file_name.dat
  3. A simple file name. If "file_name" contains no slashes (i.e., no path information), it is assumed to be in the same directory as the template file.

General rules for !include:

  • Each !include command must be on a line by itself.
  • The name of the file to include after the !include = command may not contain variable names in square brackets (i.e., you cannot build a file name with variables). !print-file does allow this. This is because Transform doesn't know the value of your variables when reading include files.
  • !include files may contain complete or parts of various template sections which include form variables in square brackets. In fact, you can use !include to read in whole sections of the template file if you like. For example:
      #begin template
      !include = standard_error_response.html
      !include = standard_success_response.html
      !include = email_section_for_this_service.txt
      #end template

    The above would be a perfectly valid template file, assuming the !include files existed.

  • Files included with !include may also contain !include commands. Any file you include with the !include command may also contain !include commands for other files.
  • In general, use !include instead of !print-file (described below) if you have complete sections, including section headers, stored in separate files.

Printing files to output (!print-file)

!print-file allows you to have information stored in a file printed out when the sections of a template file are processed. Because !print-file commands are evaluated at the final step in the process, they can take advantage of the values of your form variables (whereas !include commands cannot). The general form of the !print-file command is:

!print-file = "file_name"

Like !include, there are three possible ways to specify the "file_name":

  1. A complete path. If you type pwd (meaning "print in working directory") in any directory, you will see a complete path to that directory. To create an acceptable "file_name" for !print-file, you would add the specific include file name to the result of the pwd command. For example:
    /ip/account/some_directory/my_include_file_name.dat
  2. A path relative to your login directory. If the "file_name" begins with a tilde (~), it is assumed that the path is relative to your login directory. For example:
    ~account/some_directory/my_include_file_name.dat
  3. A simple file name. If "file_name" contains no slashes (i.e., no path information), it is assumed to be in the same directory as the template file.

Following are things you can and can't do with !print-file:

  • In general, think of the information stored in a !print-file as being output at the last minute.
  • !print-file commands must begin in the first column and be on a single line by themselves.
  • !print-file commands are allowed in all sections except the *define-variables* section, because the *define-variables* section is only used for setting variables and is never output.
  • Information stored in a !print-file may contain variable names in square brackets. Transform will replace the variable names with their values before they are output.
  • The "file_name" specified in a !print-file command may contain variable names in square brackets. For example:
    !print-file = [user].html

    If the current value for [user] were "moe", Transform would output a file named moe.html at this point in your template file (assuming the file exists in the same directory as your template).

  • Information stored in a !print-file file may not contain section headers (e.g., *success-response*), or the !commands that must immediately follow section headers (e.g., !use-if, !append-file-name) !print-files are output at the last minute; section headers and these !commands must be "known" to Transform prior to the output step. You can, however, use !print-files for everything except the section headers and initial !commands. For example:
      *email-response*
      !use-if [confirm] eq "yes"
      !print-file = "confirm_email_message.txt"
  • !print-file can be more efficient than !include, especially if the amount of information stored in external files is large. Consider the following example:

    Assume that you wanted to include the same HTML signature file at the bottom of every *error-response* and *success-response* for some set of forms/templates. Assume the following signature information was stored in a file called sig.html in the same directory as your forms/templates:

      <hr>Send comments or questions to blah@indiana.edu<hr>

    To include this signature information in any template file, you could do the following:

      # begin template
      *email-response*
      ... your email response template information...
      *success-response*
      ...any success message...
      !print-file = sig.html
      *error-response*
      ...any error message...
      !print-file = s.html
      # end template

    This would result in the sig.html file being printed at the end of the *success-response* or the *error-response* when it was displayed to the user.

    In the example above, you could use !include instead of !print-file and get the same results. The problem with using !include, however, is that your signature file, sig.html, would be read in twice (for the success and error responses) when the template is initially being built. Using !print-file, the sig.html file is only read once, when either the success or error response section is being output.

  • !print-file commands may be included in files that are read in by !print-file (i.e., a !print-file may contain !print-file, which may also contain !print-file, etc.). Collectively, a maximum of 50 !print-file commands are allowed per form submission.
  • Files read in via !print-file may contain !print-if commands.
  • If a !print-file you specify is not found, the command is simply ignored and no error message is given. This allows you to set up conditions where files are only printed if they exist. If debug mode is turned on (i.e., with !debug), an error message will be printed if the !print-file does not exist. You may want to use !debug mode when initially testing your template.
  • !print-file commands may be embedded inside !print-if blocks. This allows you to select which !print-file to output based on user input. For example:
      *success-response*
    eiou  ... whatever ...
      !print-if [color] e red
      !print-file = "my_red_file.html"
      !print-if [color] eq blue
      !print-file = "my_blue_file.html"
      !end-print-if

Controlling the lines printed from a !print-file (!begin-print-file, !end-print-file, !print-file-mode)

Using !begin-print-file, !end-print-file, and !print-file-mode, you have some control over which lines in a !print-file are actually printed. These commands are used as follows:

  !begin-print-file-with = any_begin_string
  !begin-print-file-after = any_begin_string

These two commands control where to begin printing the contents of the file. The !print-file is scanned until the first line containing "any_begin_string" is found. Printing then begins either "with" that line (using !begin-print-file-with) or with the next line (using !begin-print-file-after).

  !end-print-file-with = any_end_string
  !end-print-file-before = any_end_string

These two commands control where to stop printing the contents of the file. While printing the file, it is scanned for "any_end_string". When this string is found on a line, printing either stops immediately (using !end-print-file-before), or the line with the "any_end_string" is printed and then printing stops (using !end-print-file-with).

!print-file-mode = multi

By default, if !begin-print-file and !end-print-file are set, only the first set of lines in the file which match the begin and end criteria are printed. If !print-file-mode = multi is specified, the entire !print-file will be scanned for multiple occurrences of the begin/end criteria. Each set of lines which match the criteria will be printed in the order they're found.

General rules for using !begin-print-file, !end-print-file, and !print-file-mode:

  • These commands must precede the !print-file command they are to be applied to in your template file.
  • These commands only operate once. You must enter them separately before each !print-file command. If these commands not do not immediately precede the !print-file command, the default !print-file behavior will be used (i.e., print the whole file). For example:
      !begin-print-file-with = "the first line I want"
      !end-print-file-with =  "the last line I want"
      !print-file = "my_red_file.html"
      !print-file = "my_blue_file.html"

    The above example would result in the !begin-print-file-with and !end-print-file-with being applied to my_red_file.html, but not my_blue_file.html. All of my_blue_file.html would be printed.

  • The string you specify to mark the place to start or end printing of a file may contain variable names in square brackets (which will be replaced with their values before testing). For example, if the variable [username] had a value of "moe",
      !begin-print-file-with = [username]-line

    would cause printing to occur at the first line which contained "moe-line".

Carrying information forward to subsequent HTML forms (!carry-forward)

In advanced use, there are times when you'd like to use the *success-response* or *error-response* sections of your template to deliver an HTML form, and would like to have the variables entered in a form carried forward into the subsequent *success-response* or *error-response* form. You would use the !carry-forward command for this purpose.

Imagine a scenario where you display an initial form to the user, collect some basic registration information (e.g., "name", "address", "phone", and "course"), and then in the *success-response* for the "course" type selected by the user (see Conditional branching), you deliver another form which collects specific registration information about this particular course (e.g., "time", "date", etc). The problem is that when the user submits the course-specific form, you also need to include the "name", "address", and "phone" information from the previous form.

One way to accomplish this would be to write hidden form variable statements in the *success-response* section containing the subsequent form, setting each statement to the variables in the first form.

In general, hidden variables (variables that won't be shown to the user) can be included in any HTML form with statements like:

  <input type = hidden name = "some_name" value =
  "some_value">

If you wanted the form in the *success-response* section to include values of the name, address, and phone variables from the original submitted form, you could include the following lines:

  *success-response*
  ... any header text ...
  #begin form
  <form method = "post" action = "transform_action_statement">
  ... include any input boxes for course specific date, time, etc ..
  # now the hidden variables
  <input type = hidden name = "name" value = "[name]">
  <input type = hidden name = "address" value = "[address]">
  <input type = hidden name = "phone" value = "[phone]">
  #end form
  </form>

Note that the hidden form variable statements above have their "value =" parts set to a form variable in brackets. Like other places in a Transform template, these form variable names in brackets are replaced by the actual values supplied by the user submitting the form.

There can be a problem with this approach, however. If the user input included quotes ("), this would cause the value to be truncated in the value = part of the hidden variable when it reached the user-supplied quote. The Transform command !carry-forward allows you to avoid this problem and provides a shortcut for creating hidden variables.

!carry-forward

The purpose of the !carry-forward command is to automatically create hidden value form commands, but only for those variables that have user-submitted values. The general format of the !carry-forward command is:

  !carry-forward = [var1] [var2] [var3] etc

Using the !carry-forward command, the example above would look like so:

  *success-response*
  ... any header text ...
  #begin form
  <form method = "post" action = "transform_action_statement">
  ... include any input boxes for course specific date, time, etc ..
  # now the hidden variables
  !carry-forward = [name] [address] [phone]
  #end form
  </form>

The !carry-forward command above would cause hidden form variables statements to be included for each of the variables listed, but only if the variable had a value.

Some things to remember about using !carry-forward:

  • You can use !carry-forward in *success-response* or *error-response* sections, which are returned to the user as HTML. You may also use !carry-forward in *append-response* sections, but this would be useful only if your append file were an HTML form.
  • Hidden variable commands will only be created for those variables which have values.
  • Although no checking is done, you should only use !carry-forward within a form (i.e., between <form> and </form>). It wouldn't make sense anywhere else since hidden form variable commands are being generated.
  • !carry-forward commands cannot continue on multiple lines. You may, however, add as many !carry-forward commands as you like to include as many form variables as you need. Just be sure the line begins with !carry-forward, and each command is on a line by itself.
  • Remember that the !carry-forward command only creates hidden form variables for those form variables that have values. If you would like to have any environment variables carried forward with hidden form variables, you must create these hidden form variable statements yourself. In addition, you must give these environment variables different names. Otherwise, they will collide with the new environment variables of the same name created when the form is submitted. For example, if you wanted to carry forward an initial value of the [!TIME] variable from one form to the next, you would have to create your own variable name:
      <input type = hidden name = "initial_time" value =
      "[!TIME]">
  • While the hidden form variable statements created are not seen by the user, they are not secret. The user can view the source of the file to see the hidden form value statements. Do not try to hide any sensitive information this way.

Using !carry-forward for all variables

Using a special form of the !carry-forward command, you can have all (or all but just a few) variables carried forward. If you include the keyword all after the !carry-forward command, hidden form variables will be created for all form variables that have values. If the keyword all is followed by one or more variable names in square brackets with a hyphen/minus in front of it (e.g., -[variable]), these variables will be removed from the "all" list. For example:

  !carry-forward all

will create hidden form variables for all form variables that have values, and

  !carry-forward all -[school] -[books]

will create hidden form variables for all form variables that have values except [school] and [books].

Note:
You may only use this "all" form of !carry-forward once in any given template section. When Transform sees the !carry-forward command, it creates the hidden form variables immediately. Repeating this command would result in multiple hidden form variables for a given variable. If you need to use the -[variable] feature, all variables you want to remove from the list must be in a single !carry-forward command line.

Using Perl regular expressions in conditional tests

When building conditional tests, two comparison operators ( =~ and !~ ) give you access to Perl's regular expressions. Regular expressions offer a flexible and powerful way of testing the values of submitted form variables.

Following is a brief and incomplete introduction to using Perl regular expressions with Transform. Using regular expressions can be very complicated; this functionality is provided in Transform for advanced users who have knowledge of regular expressions.

In the conditional tests described earlier, you may include regular expression tests in the following format:

  [var] =~ regex
  [var] !~ regex

where regex is a valid Perl regular expression.

Loosely, the =~ operator means "does contain". Thus, [var] =~ regex is true if the variable [var] "does contain" (or "does match" ) the pattern defined in regex. The !~ operator is just the inverse (i.e., "does not contain" or "does not match").

Building a Perl regular expression

Building a regular expression involves defining a pattern, and then testing to see if the pattern matches (using =~) or doesn't match (using !~) the characters in the string on the left side of the expression (here, [var]). The pattern must begin and end with a slash (/). (Note that patterns may begin with m to redefine the delimiter.) For example:

  [var] =~ /Moe/

would be true if the string "Moe" was found anywhere in the variable [var].

In regular expressions, most characters simply match themselves. There are, however, some characters that have special meaning in regular expressions and do not simply match themselves. These characters include:

  \ | [ ] ( ) { } . + * ? ^ $

When using these characters in regular expressions to match themselves, they must be preceded by a backslash (\). For example, to test for the string "Moe?", put a backslash in front of the question mark:

  [var] =~ /Moe\?/

Character classes

In regular expressions, you can use some special backslashed characters to automatically match a whole set of characters. For example, \d will match any digit (i.e., 0-9). Some of these special backslashed characters include:

  \d   - A digit (0-9)
  \D   - A non-digit (not 0-9)
  \w   - A word character (a-z A-Z 0-9 and _)
  \W   - A non-word character (not in the list above)

Thus, [var] =~ /\d/ would be true if there was a digit anywhere in the variable, [var].

In addition to these character classes, a period (.) has special meaning. A period matches any character (except a newline). Thus, [var] =~ /./ would match any single character.

Specifying the number of matches

In the example above, \d matches a single digit character. Special quantifiers in regular expressions allow you to specify how many times the preceding character (e.g., a digit with \d) should match. These quantifiers include:

  {n,m}   - At least n times, but no more than m times
  {n,}    - Must match at least n times
  {n}     - Must match exactly n times
  *       - 0 or more times
  +       - 1 or more times
  ?       - 0 or 1 time

For example:

  /\d+/    - matches 1 or more digits
  /\d?/    - matches 0 or 1 digits
  /\d*/    - matches 0 or more digits (by itself this will always match)
  /\d{1,3} - matches from 1 to 3 contiguous digits

Matching the beginning, the end, or the entire string

If [var] was set to the string "help102", the following regular expression would test true:

  [var] =~ /\d+/

because zero or more digits were found in the string.

You can also test whether the string ended in digits, began with digits, or contained only digits. If the first character in a regular express is a caret (^), then the regular expression is only true if it matches from the beginning of the string. If the regular expression ends in a dollar sign ($), then the regular expression is only true if it matches from the end of the string.

For example (assume that [var] was set to "help102"):

[var] =~ /^\d+/

would test false, because [var] does not begin with one or more digits. Conversely,

  <dd>[var] =~ /\d+$/
  </dd>

would test true, because [var] does end with one or more digits.

You can combine ^ and $ in one expression to force matching against the entire string. For example:

  [var] =~ /^\d+$/

would test false, because from the beginning of the string to the end of the string, there are not just one or more digits (i.e., it begins with "help"). If [var] had been set to "1234567", the test would be true. This expression is useful for testing whether a field contains all digits. With a small change, you could test for a specific number of digits (e.g., /^\d{3}$/ must contain exactly three digits).

Match this or that or that or that

Sometimes you may want to match any one of some finite set of words (or other more complex expressions). You can do this using the vertical bar (|). For example:

  [color] =~ /red|yellow|green/

would match if [color] contained "red" or "yellow" or "green". You can also put parentheses around these groups to isolate the alternation to just that set of words. For example:

  [color] =~ /(red|yellow|green) car/

would match "red car", "yellow car", or "green car".

Match some set of characters

The last example showed how to pick between different possible words (which could have each been more complex expressions). You may also define a list of characters to match by putting them in square brackets ([ ]). For example:

  [word] =~ /[a]/

would match if [word] contains any lowercase vowels, in any order;

  [word] =~ /[A-Za-z]/

would match any upper or lowercase letter. The hyphen allows you to automatically provide a range;

  [word] =~ /[A-Z a-z]/

spaces are significant. This would match a space or any upper or lowercase letter;

  [word] =~ /[^aeiou]/

is different. If a caret (^) is the first character in the square brackets, it is treated as the inverse. In this case, rather than matching a vowel, it means match anything but a lowercase vowel.

Case insensitive matching

Use when matching any upper- or lower-case vowel; case is disregarded. Include an i after the regular expression:

  [word] =~ /[aeiou]/i

Putting it all together

The examples above mostly describe individual features of Perl regular expressions. The real power of regular expressions is that you can use all of these features in a single regular expression. Here are some more examples:

  • Match a value that looks like a course number (e.g., A100 through Z999), with a leading capital letter followed by three numbers:
      [course] =~ /^[A-Z]\d{3}$/

    Here, [A-Z] matches a single uppercase character. The \d{3} matches exactly three digits.

  • Match a value that looks like a seven-character phone number, with or without the hyphen (e.g., 8551111 or 855-1111):
      [phone] =~ /^\d{3}(-|)\d{4}$/

    Here, the first three digits are matched with \d{3}. Then, (-|) says match either hyphen or null (note there is nothing between the vertical bar and the closing parenthesis). Then, match four more digits.

  • Match a value that looks like a seven-character phone number, with or without the hyphen, that could also include an optional initial area code (e.g., 812-855-1111, 812-8551111, 8551111, or 855-1111):
      [phone] =~ /^(\d{3})?(-|)?\d{3}(-|)\d{4}$/

    Here, you would use the "?", 0, or 1 operator to match the area code 0 or 1 times with (\d{3})?. Then, you would match a hyphen (or no hyphen) after the area code 0 or 1 times with (-|)?. The rest of the expression is the same as the above phone number example.

    Note that this expression isn't quite right, because it would match -855-1111. In some cases, you may find it easiest to create two (or more) regular expressions that match the possible range of legal values and join them with "or" (e.g., [var] =~ expression or [var] =~ expression2).

  • Match a string that begins and ends with a digit (e.g., 2abcde4); what's in between doesn't matter.
      [var] =~ /^\d.*\d$/

    Here, you match on a beginning digit (^\d), followed by 0 or more of any character (.*), and finally a digit at the end of the string (\d$).

General rules for using regular expressions in Transform

  • An ill-defined regular expression will result in an error message. The error message comes from the Perl interpreter, and will attempt to clarify the problem with the expression.
  • Transform variable names in square brackets cannot appear in the expression portion of the statement. For example:
      [var] =~ /^[var2]$/

    The above example is silently illegal. Although it won't generate an error, it also won't replace [var2] with the value of this variable. This prevents user-supplied input from being part of the expression (a potential security problem).

  • Perl users should be aware that regular expressions in Transform are used only to build tests against the values of form variables. The normal replacement and variable assignment functions associated with regular expressions are meaningless in this context.
  • You must use Perl's rules for regular expressions. Some of the rules may differ from those used by other applications.

For more about Perl regular expressions, refer to a comprehensive Perl resource (e.g., Programming Perl by Tom Christiansen et al.; published by O'Reilly & Associates).

Authentication: Controlling access to your forms and documents

By default, all forms or documents in your www directory and subdirectories may be viewed by anyone on the internet. However, on the central servers, you may have some control over who can access your files. You may limit access to only users with an IU Network ID or create your own custom access control. For more, see Controlling web page access.

This form of authentication works by placing a .htaccess file in the directory containing the files you want to control access to. Note that this works on a directory-by-directory basis; the .htaccess file only restricts access to the files and subdirectories in the directory where it resides. When a user attempts to access a file (via an HTML link) in a directory containing a .htaccess file, the www server checks to see whether the user may access that directory.

Since control is on a directory-by-directory basis, you must create a special directory (or directories) for documents or forms that you want to restrict access to. You must also install Transform in this directory and point to this copy in your form action statement. For example, in your www directory, you could create a directory called net_id and place all forms and documents that you want to make available only to users with IU Network IDs in this directory.

Examples

For working examples that demonstrate some of Transform's features, see Transform Examples.

This is document bfsd in the Knowledge Base.
Last modified on 2018-05-15 10:43:58.

Contact us

For help or to comment, email the UITS Support Center.