NAME

CGI::FormMagick - easily create CGI form-based applications

SYNOPSIS

use CGI::FormMagick;

my $f = new CGI::FormMagick();

# all options available to new()
my $f = new CGI::FormMagick(
    TYPE => FILE,  
    SOURCE => $myxmlfile, 
    DEBUG => 1
    SESSIONDIR = "/tmp/session-tokens"
    PREVIOUSBUTTON = 1,
    RESETBUTTON = 0,
    STARTOVERLINK = 0
);

# other types available
my $f = new CGI::FormMagick(TYPE => STRING,  SOURCE => $data );

$f->add_lexicon("fr", { "Yes" => "Oui", "No" => "Non"});

$f->display();

DESCRIPTION

FormMagick is a toolkit for easily building fairly complex form-based web applications. It allows the developer to specify the structure of a multi-page "wizard" style form using XML, then display that form using only a few lines of Perl.

How it works:

You (the developer) provide at least:

  • Form descriptions (XML)

  • HTML templates (Text::Template format) for the page headers and footers

And may optionally provide:

  • L10N lexicon entries

  • Validation routines for user input data

  • Routines to run before or after a page of the form is displayed

FormMagick brings them all together to create a full application.

METHODS

new()

The new() method requires no arguments, but may take the following optional arguments (as a hash):

TYPE

Defaults to "FILE" (the only currently implemented type). Eventually we'll also allow such things as FILEHANDLE, STRING, etc (c.f. Text::Template, which does this quite nicely).

SOURCE

Defaults to a filename matching that of your script, only with an extension of .xml (we got this idea from XML::Simple).

DEBUG

Defaults to 0 (no debug output). Setting it to 1 (or any other true value) will cause debugging messages to be output.

PREVIOUSBUTTON

Defaults to 1 ("Previous" button is shown).

RESETBUTTON

Defaults to 1 ("Clear this form" button is shown).

Defaults to 1 ("Start over" link at the bottom of the page is shown).

display()

The display method displays your form. It takes no arguments.

add_lexicon()

This method takes two arguments. The first is a two-letter string representing the language to which entries should be added. These are standard ISO language abbreviations, eg "en" for English, "fr" for French, "de" for German, etc.

The second argument is a hashref in which the keys of the hash are the phrases to be translated and the values are the translations.

For more information about how localization (L10N) works in FormMagick, see CGI::FormMagick::L10N.

debug($msg)

The debug method prints out a nicely formatted debug message. It's usually called from your script as $f-debug($msg)>

SECURITY CONSIDERATIONS AND METHODS FOR MANUAL VALIDATION

If you use page POST-EVENT or PRE-EVENT routines which perform code which is in any way based on user input, your application may be susceptible to a security exploit.

The exploit can occur as follows:

Imagine you have an application with three pages. Page 1 has fields A, B and C. Page 2 has fields D, E and F. Page 3 has fields G, H and I.

The user fills in page 1 and the data FOR THAT PAGE is validated before they're allowed to move on to page 2. When they fill in page 2, the data FOR THAT PAGE is validated before they can move on. Ditto for page 3.

If the user saves a copy of page 2 and edits it to contain an extra field, "A", with an invalid value, then submits that page back to FormMagick, the added field "A" will NOT be validated.

This is because FormMagick relies on the XML description of the page to know what fields to validate. Only the current page's fields are validated, until the very end when all the fields are revalidated one last time before the FORM POST-EVENT is run. This means that we don't suffer the load of validating everything every time, and it will work fine for most applications.

However, if you need to run PAGE POST-EVENT or PRE-EVENT routines that rely on previous pages' data, you should validate it manually in your POST-EVENT or PRE-EVENT routine. The following methods are used internally by FormMagick for its validation, but may also be useful to developers.

Note: this stuff may be buggy. Please let us know how you go with it.

$fm->validate_field($cgi, $fieldname | $fieldref)

This routine allows you to validate a specific field by hand if you need to. It returns a string with the error message if validation fails, or the string "OK" on success.

Examples of use:

This is how you'd probably call it from your script:

if ($fm->validate_field($cgi, "credit_card_number") eq "OK")) { }

FormMagick uses references to a field object, internally:

if ($fm->validate_field($cgi, $fieldref) eq "OK")) { }

(that's so that FormMagick can easily loop through the fields in a page; you shouldn't need to do that)

$fm->validate_page($cgi, ($number | $name | $pageref))

This routine allows you to validate a single page worth of fields. It can accept either a page number (counting naturally from one, NOT starting at zero), a page name, or a reference to a page object. You'll probably want to use the name or number; the page reference is used internally by FormMagick's validate_all() routine to loop through all the pages in the form.

This routine returns a hash of errors, with the keys being the names of fields which have errors and the values being the error messages. You can test for whether something's passed validation by testing for a true return value.

Examples:

my %errors = $fm->validate_page($cgi, 3);
my %errors = $fm->validate_page($cgi, "CreditCardDetails");
if (%errors) { ... }

$fm->validate_all($cgi)

This routine goes through all the pages that have been visited (using FormMagick's built-in page stack to keep track of which these are) and runs validate_page() on each of them.

It returns a hash the same as validate_page().

FORMMAGICK XML TUTORIAL

Form descriptions

The following is an example of how a form is described in XML. More complete examples can be found in the examples/ subdirectory in the CGI::FormMagick distribution.

  <FORM TITLE="My form application" HEADER="myform_header.tmpl" 
    FOOTER="myform_footer.tmpl" POST-EVENT="submit_order">
    <PAGE NAME="Personal" TITLE="Personal details" DESCRIPTION="Please
    provide us with the following personal details for our records">
      <FIELD ID="firstname" LABEL="Your first name" TYPE="TEXT" 
        VALIDATION="nonblank"/>
      <FIELD ID="lastname" LABEL="Your surname" TYPE="TEXT" 
        VALIDATION="nonblank"/>
      <FIELD ID="username" LABEL="Choose a username" TYPE="TEXT" 
        VALIDATION="username" DESCRIPTION="Your username must
	be between 3 and 8 characters in length and contain only letters
	and numbers."/>
    </PAGE>
    <PAGE NAME="Payment" TITLE="Payment details"
    POST-EVENT="check_credit_card" DESCRIPTION="We need your full credit
    card details to process your order.  Please fill in all fields.
    Your card will be charged within 48 hours.">
      <FIELD ID="cardtype" LABEL="Credit card type" TYPE="SELECT" 
        OPTIONS="list_credit_card_types" VALIDATION="credit_card_type"
		MULTIPLE="NO"/>
      <FIELD ID="cardnumber" LABEL="Credit card number" TYPE="TEXT" 
        VALIDATION="credit_card_number"/>
      <FIELD ID="cardexpiry" LABEL="Expiry date (MM/YY)" TYPE="TEXT" 
        VALIDATION="credit_card_expiry"/>
    </PAGE>
    <PAGE NAME="Random" TITLE="Random fields">
      <FIELD ID="confirm" LABEL="Click here to confirm" TYPE="CHECKBOX"
        VALUE="confirm" CHECKED="0"/>
      <FIELD ID="color" LABEL="Choose a color" TYPE="RADIO"
        OPTIONS="'red', 'green', 'blue'"/>
    </PAGE>
  </FORM>

The XML must comply with the FormMagick DTD (included in the distribution as FormMagick.dtd). A command-line tool to test compliance is planned for a future release.

Field parameters

Fields must ALWAYS have an ID value. Optional parameters are:

  • LABEL (a short description)

  • DESCRIPTION (a more verbose description)

  • VALUE (see below)

  • VALIDATION (a list of validation functions: see CGI::FM::Validator)

  • VALIDATION-ERROR-MESSAGE

  • TYPE (see below)

  • OPTIONS (see below)

  • CHECKED (for CHECKBOX fields, does this start off checked?)

  • MULTIPLE (for SELECT fields, can user select more than one value?)

  • SIZE (for SELECT fields, height; for TEXT and TEXTAREA fields, length)

The following field types are supported:

  • TEXT

  • TEXT (SIZE attribute is optional)

  • SELECT (requires OPTIONS attribute, MULTIPLE and SIZE are optional)

  • RADIO (requires OPTIONS attribute)

  • CHECKBOX (CHECKED attribute is optional)

Notes on parsing of VALUE attribute

If your VALUE attribute ends in parens, it'll be taken as a subroutine to run. Otherwise, it'll just be taken as a literal.

This will be literal:

VALUE="username"

This will run a subroutine:

VALUE="get_username()"

The subroutine will be passed the $cgi object as an argument, so you can use the CGI params to help you generate the value you need.

Your subroutine should return a string containing the value you want.

Notes on parsing of OPTIONS attribute

The OPTIONS attribute has automagical Do What I Mean (DWIM) abilities. You can give it a value which looks like a Perl list, a Perl hash, or a subroutine name. For instance:

OPTIONS="'red', 'green', 'blue'"

OPTIONS="'ff0000' => 'red', '00ff00' => 'green', '0000ff' => 'blue'"

OPTIONS="get_colors()"

How it works is that FormMagick looks for the => operator, and if it finds it it evals the OPTIONS string and assigns the result to a hash. If it finds a comma (but no little => arrows) it figures it's a list, and evals it and assigns the results to an array. Otherwise, it tries to interpret what's there as the name of a subroutine in the scope of the script that called FormMagick.

A few gotchas to look out for:

  • Make sure you quote strings in lists and hashes. "red,blue,green" will fail (silently) because of the barewords.

  • Single-element lists ("red") will fail because the DWIM parsing doesn't find a comma there and treats it as the name of a subroutine. But then, a single-element radio button group or select dropdown is pretty meaningless anyway, so why would you do that?

  • Arrays will result in options being sorted in the same order they were listed. Hashes will be sorted by key using the default Perl sort().

  • An anti-gotcha: subroutine names do not require the parens on them. "get_colors" and "get_colors()" will work the same.

SEE ALSO

CGI::FormMagick::L10N

CGI::FormMagick::Validator

CGI::FormMagick::FAQ

BUGS

The VALIDATION attribute must be very carefully formatted, with spaces between the names of routines but not between the arguments to a routine. See description above.

AUTHOR

Kirrily "Skud" Robert <skud@infotrope.net>

Contributors:

Shane R. Landrum <slandrum@turing.csc.smith.edu>

James Ramirez <jamesr@cogs.susx.ac.uk>

More information about FormMagick may be found at http://sourceforge.net/projects/formmagick/