InputForms-Original

Summary: Adding Input form markup (out of date) Version: 2005-09-06 (last page update) Prerequisites: Status: superseded by PmWiki's Input? form markup Maintainer: Categories: Forms Superseded CookbookToDo

<< | Forms-related? | >>

WARNING: This recipe was broken by a change in PmWiki 2.0beta44. It will be fixed in due course, but it will take a while until I have sorted out the mess.
Note that the new version will have some changed defaults and parameter names for better uniformity with PmWiki core syntax. I also plan to move most of the documentation to Forms?, and maybe rename the recipe since it will be more an add-on to existing functionality than a separate recipe.
Joachim Durchholz September 06, 2005, at 02:23 PM

Update: Sorry, I haven't found the time to update the recipe, nor is it likely that this will happen within the next few months. The Real World keeps interfering... :-(
If anybody is willing to start work, I'll gladly help. Things to be done include:

  • Check where this recipe and the PmWiki core for form input overlap, and where they conflict.
  • For overlaps, simply remove the functionality from this recipe.
  • For conflicts of syntax, it's probably an inconsistency. Adapt this recipe to be consistent to the way that the PmWiki core handles it.
  • It might be a good idea to rip out most of the form generation engine and simply hook into what the PmWiki core does. The PmWiki core has very weak error-checking capabilities, so it's a pity to do that, but it doesn't make sense to keep error checking just for a few add-on input facilities.
  • For semantic conflicts, investigate the situation and determine what to do.

The remains will probably be just a small add-on that defines those input controls that the PmWiki core neglected. Maybe it will define some additional options for the input controls already defined in the core.
Joachim Durchholz February 28, 2006, at 12:34 PM

Question

How do I create an input form?

Answer

Download Attach:input.php into your cookbook/ directory and add

  include_once('cookbook/input.php');

to your config.php.

input.php will define the (:input ...:) markup that allows to define an HTML input form. It does not cover receiving the input data or generating an HTML response - that's the domain of an external CGI script or yet another recipe.

Markups

Parameters in the (:input ...:) markup are subject to the following rules:

Mandatory parameters are given as parts of the markup syntax, e.g.

(:input data name value:)

Text in monospaced font must be given as shown, text in monospaced italics is a placeholder.

Optional parameters may be inserted in any order between the last mandatory parameter and the closing :) colon-and-parenthese.
An optional parameter can be a single name as in

readonly

or a name-value pair delimited by an equals sign as in

text=text

The equals sign can be surrounded by blanks.

Parameter values may be enclosed in double quotes; those that aren't end at the first blank.
To include a double-quote or backslash character in a parameter value, precede it with a backslash. (This applies even if the value isn't in double quotes.)

Most markups have a name parameter. Such a name is used to identify data that's submitted for processing, so in most cases, it must be unique between (:input start...:) and (:inputend:).

Most errors in an (:input...:) markup will result in an error message on the wiki page.

Forms

(:input start script:)

This starts an input form.

As an exception, this markup must be first on its line.

Parameters:

script
This must be the URL of a CGI script. To submit to a PmWiki recipe that installs an action handler, write 'http://your.domain.tld/path/to/pmwiki?action=handler'.
method=method/submethod
This determines the method to use for submitting form data. Available values are:
post or post/binary
This is the default. It sends the data using the POST method with a multipart/form-data encoding. It is the only method that can transmit arbitrary binary or UTF data without problems.
post/urlencoded
Not recommended because it cannot handle characters beyond the 8-bit ASCII range. Provided for compatibility with existing CGI scripts that expect input data in the form of the POST method with application/x-www-form-urlencoded data.
post/text
This sends the data using the POST method with a text/plain encoding. This is mostly useful if the sent data is not processed by a program but by a human, e.g. if the script URL is a mailto: address; not recommended for other purposes, except for compatibility with CGI scripts that expect their data in text/plain format.
get
Not recommended because it cannot handle characters beyond the 8-bit ASCII range. I also suspect that PHP cannot properly decode the data for multi-selectable menus and multiple checkboxes with the same name. Provided for compatibility with existing CGI scripts that expect input data in the form of the GET method with application/x-www-form-urlencoded data.
Submitted data will come in the form of name=value pairs. CGI scripts written in PHP can pick these off from $_POST['name'] (or $_GET['name'] if method=get). For most PHP versions, this data will also be available in $_REQUEST['name'] regardless of the method setting, but some PHP versions didn't fully populate $_REQUEST.

(:input end:)

This finishes the input form.

As an exception, this markup must be first on its line.

The blank space between input and end is optional.

You need not specify this markup; the recipe will automatically insert it before the next (:input start...:) or the end of the page.

(:input button name label:)

This creates a button control that, when clicked, will submit the current state of the input form to the WWW server.

The label parameter gives the label to show on the button.

The only available optional parameter is:

disabled
The button does not react to clicking.

The clicked button will submit name=label; any other buttons will not submit anything.

(:input hidden name value:)

This provides data for the script without showing it to the visitor.
It creates a "hidden input field" that will submit name=value.

Note that this control is provided only for compatibility with non-PHP scripts that can't access session variables. To pass hidden data to a PHP-based script, simply assign the value to a session variable like

  $_SESSION['recipe_name']['name']

and the data will remain available throughout the browser session.

Text input

(:input line name:)

This creates a single-line input control.

Available optional parameters are:

columns=number
The number of visible text characters. (Users may be able to enter more or less characters; see maxcolumns, below.)
disabled
The text in the input control isn't transmitted when the user submits the form.
maxcolumns=number:
The maximum number of characters that the control will accept.
password
User input is just shown as a series of stars (useful for password input). Note that this protects against people spying over the visitor's shoulders, to protect from people logging the network traffic you'd need an encrypted connection (i.e. HTTPS or a VPN).
readonly
The control's value or state cannot be changed by the visitor if this parameter is present.
This attribute does not affect the sending of values to the script.
text="text"
The text to pre-fill the input control with.

(:input text name:)

This creates a multi-line input control.
Note that it's impossible to limit the size of the input in such a control. However, both WWW servers and PHP installations are usually configured to reject any requests that exceed a given byte size.

It will submit name = text, where text is the contents of the text field at the time of submission.

Available optional parameters are:

columns=columns
Number of visible text columns. (Visitors can enter wider text. This just limits the optical size of the control, not its capacity.)
The default value is 65.
disabled
The text in the input control isn't transmitted when the user submits the form.
readonly
The control's value or state cannot be changed by the visitor if this parameter is present.
This attribute does not affect the sending of values to the script.
rows=rows
Number of visible text rows. (Visitors can enter longer text. This just limits the optical size of the control, not its capacity.)
The default value is 5.
text="text"
The text to pre-fill the input control with. Unfortunately, there is currently no way to specify an end-of-line within the text.

Choices

(:input checkbox name:)

This creates a checkbox control.

Available optional parameters are:

disabled
The value of the input control isn't transmitted when the user submits the form, even if the control is checked.
checked
The checkbox will be marked as checked if this parameter is present.
value=text
The value to submit if the checkbox is checked.

HTML allows that multiple checkboxes may have the same name. This doesn't work properly with this recipe though: the values would all get written to the same variable, and you'd get only the last value written. So, it's better to use different names for each checkbox.

(:input radiobutton name:)

This creates one of a set of radio-button controls.

Multiple radio-button controls may have the same name. Together, these radio buttons form a radio button group: if one of them gets checked, all others in the group are automatically unchecked.

This control takes exactly the same optional parameters as checkbox.

(:input menu name:)

This begins a menu. Optional parameters are:

disabled
The entries in the menu cannot be checked or unchecked by the visitor, and the menu doesn't submit data.
lines
How many lines to display. Most if not all browsers make the menu a drop-down list if this is 1, and a scrollable list with lines lines visible if this is more than 1. The default is 1.
multiple
The menu allows selecting multiple items.

The only thing between (:input menustart...:) and (:input menuend:) should be (:input menuentry...:), (:input menugroup...:), or (:input menugroupend:) markup.

If the multiple option is set, name will automatically have a pair of square brackets appended. If the data is sent to a PHP script, this will cause PHP to automatically extract any multiple values and place them in an array.

Example:
If a menu without multiple is written like this:

  
  (:input menu single-select-menu:)
  (:input menuentry 'menu entry #1':)
  (:input menuentry 'menu entry #2':)
  (:input menuend:)
  

and the user selects the first menu entry, a PHP script would see

  
  $_REQUEST['single-select-menu'] == 'menu entry #1'
  

For a menu with multiple like this:

  
  (:input menu multi-select-menu multiple:)
  (:input menuentry 'menu entry #3':)
  (:input menuentry 'menu entry #4':)
  (:input menuend:)
  

with both menu entries selected, the PHP script would see

  
  $_REQUEST['multi-select-menu'][0] == 'menu entry #3'
  $_REQUEST['multi-select-menu'][1] == 'menu entry #4'
  

A non-PHP script will see this:

  
  single-select-menu=menu entry #1
  

and

  
  multi-select-menu[]=menu entry #3
  multi-select-menu[]=menu entry #4
  

Note: While this is called "menu" here and in the HTML standards, most browsers implement this as a scrollable list box or as a drop-down list.

(:input menugroup name:)

This begins a submenu. The only optional parameter is:

disabled
The entries in the submenu cannot be checked or unchecked by the visitor, and the menu entries don't submit data.
Note that MS Internet Explorer as of version 6.0 doesn't honor this option. If you disable the submenu, you should also disable each entry in it.

Note that the current HTML standard doesn't allow nested submenus. This limitation is expected to be lifted in the next version of HTML; in other words, it will take years until the majority of browsers can be expected to support nested submenus.

(:input menugroupend:)

This ends a submenu. Every (:input menugroup...:) must be finished off with an (:input menugroupend:) to generate standards-compliant HTML.

(:input menuentry value:)

This creates a menu entry that displays the value. Optional parameters are:

checked
The menu entry is checked when it is first displayed. The user can check or uncheck it (unless it is disabled).
disabled
The menu entry is disabled. The user cannot manipulate it, and the value is never submitted to the script.

(:input menuend:)

This ends a menu. Every (:input menustart...:) must be finished off with an (:input menuend:) to generate standards-compliant HTML.

Testing your forms

There are two ways to easily test your forms.

One is specifying a mailto: URL in the (:input start...:) markup. Actually the HTML specification leaves the browser's behavior unspecified in this case, but at least Mozilla is known to open a mail window with the name=value pairs ready for human inspection.
To make this work, you must specify method=post/text as well.
To sum it up, the first line of the form should read

  (:input start script='mailto:any@where' method='post/text':)

The other is sending it to your own PmWiki installation with ?action=diag. PmWiki will then dump all its global variables.
Just make sure you have

  $EnableDiag = 1;

set in your config.php. The first form line would look something like

  (:input start script='http://doma.in/path-to-wiki?action=diag':)

Just search the output for the names of your controls and you'll find the variables where the data is submitted (it's quite likely that you'll find the same data in multiple places). Note that the places where the form data can be found will be the same for all PHP scripts, whether they are part of a PmWiki script or stand-alone.
When comparing this approach to the mailto: approach, it has the advantages that you can directly see the PHP variables that will get the form data, and that you don't need a specific browser; it has the disadvantage that you have to sift through lots of irrelevant data.

Notes and Comments

  • This recipe was last tested on PmWiki version: 2.0beta37
  • This recipe requires at least PmWiki version: 2.0

All positional parameters (such as script in (:input start...:)) can also be given in name=value form. I.e. instead of

  (:input start 'http://...':)

you can also write

  (:input start script='http://...':)

so that both you and anybody who edits that markup sees a bit more precisely what's going on.
This effect was initially a side-effect of the way that parameter parsing was done, but it's considered a permanent feature now.
Note that the order must still be preserved. This is classified as an annoyance - please feel free to improve the code.
Joachim Durchholz July 06, 2005, at 05:18 PM

File controls are not covered. I didn't have the time to explore all the ramifications of allowing uploads, such as whether the uploads should go to the standard upload directory or a freely specified one. However, on the technical side of things, the recipe has been programmed to allow uploads.
Joachim Durchholz May 20, 2005, at 04:21 PM

Bugs

The (:input end:) before the end of a page (or table cell) isn't generated automatically. This means the the generated HTML will be invalid, but it will still work fine on the vast majority of browsers.
This bug is currently unfixable, since the hooks that PmWiki uses to close off nested unclosed HTML structures aren't fit for use by a recipe.
The current workaround is to explicitly close off any (:input start...:) with an (:input end:).

(:input menu...:) isn't implemented yet. Actually the syntax may change drastically, since implementing the nearly-nested structure as described above carries some technical complications.

See Also

CompareFormsRecipes?

Change and contribution history

DateContributorVer.Comments
2005-06-26Joachim Durchholz First alpha release.
2005-06-28Joachim Durchholz0.1Adaption to Module Guidelines?.
Made (:form end:) optional.
2005-06-28Joachim Durchholz0.2Defined (:input start...:) and (:input end:) to be block markup, which is necessary to generate compliant HTML. This also implies that these markups must be first on a line (which is OK since HTML <form...> tags start a new paragraph anyway).
2005-06-29Joachim Durchholz0.3Simplified session support (we don't need any...). (:input data...:) consequently renamed to (:input hidden...:) since its only purpose is now generating an <input hidden...> tag to communicate with non-PHP scripts.
2005-06-30Joachim Durchholz0.4Implementation change: Reduced the number of markup rules to 1. This makes it easier to add markup before or after it (relevant improvement for "building block" recipes like this one).
2005-07-04Joachim Durchholz0.5Fixed an embarassing bug in HTML generation. Thanks to Christian Schlatter for diagnosing it and providing a correction.
2005-07-07Joachim Durchholz0.90Finished alpha tests.
Slight improvements in error reporting.
Fixed numerous bugs in HTML option generation.
Changed keywords in (:input start method=...:) to better reflect the wikipage author's view of the world.
2005-07-07Joachim Durchholz0.91Fixed recognition of second and subsequent (:input...:) markup on a wikitext line.
Fixed inadvertent generation of paragraphs when an (:input...:) markup was first on a wikitext line.
2005-07-07Joachim Durchholz0.92Added (:input menu...:) markup.
2005-07-09Joachim Durchholz0.93Fixed a bug in the definition of INPUT_VERSION (that bug is inconsequential unless somebody else defined INPUT_VERSION).
2005-07-11Joachim Durchholz0.94Bug fix: Will now generate default values for those HTML attributes that are required by the HTML standard.