Php WebForms

Project Setup

Download the source archive WebForms.zip. Extract/install it into your /default website folder and and set it up as a Php Application with Existing Sources (see Php Basics) or Php Application from Remote Server, (see Remote NetBeans Project).

This application is based on the Php Web Starter project, and so it employs Smarty Templates. On MAC or Linux systems you should run this command from the WebForms directory to ensure web writability of the Smarty template cache directory:
$ chmod 777 app/cache

Web applications

In a Web application, the user interacts with a web page via HTML form elements and/or hyperlinks. After making choices and/or clicking some element (like a button), data is submitted to a program which then generates the next web page, and so on.

Web applications have a very different style than Java GUI applications. Both are event-driven through GUI interfaces, but instead of being a single program, a web application acts as a series of programs which start and terminate for each generated response. The term stateless of often used to describe a web application in the simplest sense because it produces its output solely on the incoming parameters. A key ingredient is introducing state into the applications through database and or session usage.

Another feature of web applications is that the responses are normally stacked. This is what the "Back" button in the browser is all about, the maintenance of a URL history with the ability to go back to previous activations. This history has both good and bad points. It gives the user the ability to retrace his/her steps, but if a web activation represents a "one-time" transaction, like deleting a database record, then the notion of going back to that activation is error-prone at best.

Request data processing

Web data is transmitted as a list of parameters/values in a data string constructed, by default, like this:
name1=value1&name2=value2&...
where name1, name2, etc., correspond to the values of name attributes of form elements and the values are somehow generated by these form elements. In most circumstances a parameter name appears only once (single-valued), but it is possible for it to appear more than once (multi-valued). This construction of parameter/value encoding is referred to as application/x-www-form-urlencoded.

A GET request sends this encoded parameter data string attached to the script's URL in the form of a query string following a ? after the script name:
http://.../SCRIPT?name1=value1&name2=value2&...
A POST request sends the parameter string to the script which receives it through an external input stream. There are reasons for choosing to use GET or POST queries: The GET method is the method used by standard hyperlink activations and is the default used by an form element. Web database-driven applications generally prefer the POST method. Some key points are:

Php parameter processing

In Php, parameter name/value pairs are processed and made available via these superglobal array maps:
$_GET$_POST$_REQUEST
$_GET['param'] and $_POST['param'], as suggested, hold the value of parameter param obtained as by GET or POST, respectively. $_REQUEST is effectively a merge of these two maps, representing either a GET or POST parameter. If there is no such parameter param, the value is undefined.

A multi-valued parameter for Php processing appears in the data string with brackets, typically like this:
name[]=value
In this case Php will regard $_REQUEST['name'] as an array (or undefined).

The Php filter_input function

Although we can obtain parameter values directly from the superglobals $_REQUEST, etc., it is recommended to obtain these using the dedicated filter_input function. In the simplest usage we would write:
$param = filter_input( INPUT_POST, 'param' );
to extract the parameter value. If there is no such parameter, the variable value is NULL, but not undefined. The rough equivalent is the more complex construction which must first tests for definedness:
$param = isset($_POST['param']) ? $_POST['param'] : null;
One advantage of the filter_input function is to circumvent the limitation of undefined parameters. An optional third argument in filter_input dictates the type of filtering; an optional fourth argument dictates other aspects of processing. For example, a multi-valued parameter, array_param, should use this call:
$array_param = filter_input( INPUT_POST, 'array_param', 
                             FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
which will return either an array of values or null if array_param is not one of the parameters.

The web server environment

The web server environment in Php is represented by the superglobal variable $_SERVER which can assess other dynamic information about the script's activation: Here are some examples: A simple Php program which dumps the superglobal $_SERVER array is this:
<pre>
<?php print_r($_SERVER) ?>
</pre>
Like request variables, server variables are better accessed using the filter_input function, this time with INPUT_ENV as the first argument. For example, to retrieve the client IP accessing the site, use:
$client_ip = filter_input(INPUT_SERVER, 'REMOTE_ADDR');

Forms and Components

An HTML form is enclosed within the tags:
<form action="PROGRAM" method="METHOD" target="TARGET">
  <!-- form elements -->
</form>

Form Elements

The HTML form elements provide the user interface. They consist of

Attributes

HTML elements use attributes specific to the element to change the appearance or behavior. Attributes are name/value pairs within the start tag of an element:
<elt attr1="value1" attr2="value2" ... >
Certain attributes, called boolean attributes, have no value and are activated simply be being present. Here are some examples:
selected    (sets a chosen element in a selection list)
checked     (sets a chosen element in a radio or checkbox group)
disabled    (makes it unusable)
readonly    (makes text-based elements uneditable)
multiple    (permits multiple selection in a selection list)

Reentrant activations

When creating a form within a Php script, the first choice to make is determining the action attribute, i.e., what is the handler script which will process the form data? The choices are: In some sense the first choice is simplest; however the question is: why would a script go back to itself? Actually, you see this all the time in practice. A reentrant activation is often used when you are trying to submit some data and there is an error. The reentrant activation gives you the chance to correct the error. The simplest way to create a reentrant activation is by making the action the script name itself:

some_script.php
<form action="some_script.php" method="...">
...
</form>
The only problem with this approach is that you have to change the action if you change the name of the script. An alternative is to have Php dynamically compute the script name:
$self = filter_input(INPUT_ENV, 'PHP_SELF');
...
<form action="<?php echo $self ?>" method="...">
...
</form>

Initial versus reentrant activations

A form which calls itself will typically have very different behaviors on the initial activation called "from the outside" versus reentrant activations called from the form. We need some way to programmatically differentiate these two activations. Some basic characteristics of the two activations are these: Based on this knowledge, some common approaches to differentiating initial vs. reentrant are:

Sticky form elements

A static form element, without any programming features, used in a reentrant script will lose its value when the form is submitted. It is almost always preferable to maintain the values of form elements in reentrant activations because in many cases the user is simply trying to correct some field and does not need to reenter all field values.

A form field is called called sticky if it maintains its value on reentrant activation. To achieve this you have capture the parameter value(s) sent by the form, and use these values to reset the form elements accordingly.

Smarty Templates

We are going to generate forms using Smarty Templates. As you will see, Smarty provides a number of very useful support functions for simplifying the code generation of form elements. Our application features form scripts illustrating three types of elements: The forms are written using both Smarty Templates and Pure Php to offer a comparison. Our exposition will focus on the Smarty versions. The most striking simplification of Smarty is, of course, that the template scripts need not contain the full HTML code which is hidden away in the layout.tpl file.

Initial versus reentrant activations

Using Smarty templates often allows us to write simpler code for reentrant scripts precisely because the controller is separate from the view. Make the initial and reentrant activations be separated controller scripts which use the same Smarty view script.

initial.php
// set up variables (if any) 
// which give the form its 
// initial state
$data = [
  ...
];
$smarty->assign($data);
$smarty->display("common.tpl");

reentrant.php
// process params sent by
// form activation; either 
// reenter form or relocate
$data = [
   ...
];
$smarty->assign($data);
$smarty->display("common.tpl");

common.tpl
<form action='reentrant.php' method='post'>
 
   ...
 
</form>
The examples below have trivial controller usage, and so it behooves us to merge the initial and reentrant controllers into just one.

Text Elements

The HTML input element is used to create a variety of different components including textfields, buttons, hidden inputs, checkboxes, radio buttons, etc. The input element has the form:
<input type="TYPE" name="NAME" value="VALUE" ... />
where the NAME identifies the parameter passed to the action script. The TYPE values of interest now are: The HTML textarea element is used to create multiline text entry elements. It has the form:
<textarea name="NAME" rows="ROWS" cols="COLS" ... >...</textarea>
where the NAME identifies the parameter name passed to the action script. These attributes are also used to control behavior of textfields and textareas:

Buttons

A button has two different HTML representations, either as an input element or a button element:
<input type="submit" name="NAME" value="Label" />
<!-- or -->
<button type="submit" name="NAME" value="VALUE">Label</button>
For the input element, the parameter/value pair sent is NAME=Label on submission, whereas for the button element, the parameter/value pair sent is NAME=VALUE. You see that a button element is more general in that

Sanitizing Text Input

Text elements differ from other form components in that the user controls the value associated with a parameter name. When you want to display user-generated input in a target script, you have to deal with the fact that this input may contain certain HTML-special characters, in particular these:
<   &   "   >
You can leave the characters alone, assuming that the input is to be rendered as HTML or, more commonly, translate into HTML special codes so that they are rendered literally:
<    →    &lt;
&    →    &amp;
"    →    &quot;
>    →    &gt;
The procedure of turning HTML-special characters into these codes is called HTML-escaping and every Web programming system has a way of achieving these translations.

Smarty Text Element Example

The following example illustrates a reentrant form containing a textfield and a textarea. Making the form reentrant is very easy with Smarty's help in capturing the name of the script through a server variable:
<form action="{$smarty.server.PHP_SELF}" method="post">
The means of making the textfield with name="tf" sticky is to capture the value of the parameter:
$tf = filter_input(INPUT_POST, 'tf');
and then insert this value into the textfield within the template as:
<input type="text" name="tf" value="{$tf|escape:'html'}" />
These are the scripts used:

text.php
<?php
require_once "include/smarty.php";
 
//print_r($_POST);  // debug: see the parameters
 
$tf = filter_input(INPUT_POST, 'tf');
$ta = filter_input(INPUT_POST, 'ta');
$doit = filter_input(INPUT_POST, 'doit');
 
if (!is_null($doit)) {
  echo "reentrant";
}
else {
  echo "initial";
}
 
$data = [
    'tf' => $tf,
    'ta' => $ta,
];
$smarty->assign($data);
$smarty->display("text.tpl");

templates/text.tpl
{extends file="layout.tpl"}
 
{block name="content"}
  <h2>Text Form</h2>
  <form action="{$smarty.server.PHP_SELF}" method="post">
    <table class="table-condensed">
      <tr>
        <td>tf: </td>
        <td><input type="text" name="tf" value="{$tf|escape:'html'}" /></td>
      </tr>
      <tr>
        <td>ta:</td>
        <td><textarea name="ta">{$ta|escape:'html'}</textarea></td>
      </tr>
      <tr>
        <td></td>
        <td><button type="submit" name="doit">Submit</button></td>
      </tr>
    </table>
  </form>
{/block}
The inserted expression
{$tf|escape:'html'}
takes the raw output {$tf} and sends it through the escape:'html' filter. It is exactly what we want in that it performs the desired HTML-escaping of the field content. The textarea handling is completely analogous; the only difference is that the reinserted content is dropped within the textarea start and end tags.

You can test the effectiveness of the HTML-escaping in a simple way:
  1. Type some "number" (double quotes) into the textfield, submit, and observe the sticky behavior.
  2. Look at the page source and observe that the double quotes within the content have been converted into their character code values ".
  3. Start over, changing the text field within the template as indicated to use the raw output. Refresh the browser to pick up the changes.
    <input type="text" name="tf" value="{$tf}" />
  4. Re-run the same experiment. This time you'll see the textfield show only some after submission.

Single Selection Elements

Selection elements are selection lists, radio buttons and checkboxes. They give the user a limited number of choices from which we can select one or more values.

Radio/Checkbox Elements

These types of elements are often used in groups in which the elements have the same name attribute value. The effect on checkboxes is to create multi-valued parameter data, whereas with radio buttons the data is single-valued because radio button group selection is mutually exclusive.

The HTML input element is also used to create checkboxes and radio buttons. We use:
<label><input type="TYPE" name="NAME" value="VALUE" ... /> label</label>
The external label tag is optional, but it makes it so that you can activate the radio/checkbox element by clicking the label as well as the element.

To use such elements in a group, assign the same NAME, e.g.,
<label><input type="radio" name="rgp" value="value1" ... /> label1</label>
<label><input type="radio" name="rgp" value="value2" ... /> label2</label>
<label><input type="radio" name="rgp" value="value3" ... /> label3</label>
By default, nothing is selected in a radio or checkbox group, but you can do so by adding the checked boolean attribute:
<input type="TYPE" name="rgp" value="value3" checked /> LABEL
A radio group permits only one checked element whereas a checkbox group permits more than one.

Selection Lists

The HTML select and option elements are used to create selection lists. The format is like this:
<select name="NAME" ... >
  <option value="VALUE">label</option>
  ...
</select>
By default, the first option is the selected one, but you can change this by adding the selected boolean attribute into the option element:
<option value="VALUE" selected>label</option>
Additional attributes for select include these:

Single Selection Elements

Selection-based form elements which are single-valued, e.g., can be regarded in pretty much the same way. The key distinction among these elements is as follows:

Selection Example


select.php
<?php
require_once "include/smarty.php";
 
$entries = [ "aa"=>"Choice1", "bb"=>"Choice2", "cc"=>"Choice3", ];
 
//print_r($_POST);  // debug: see the parameters
 
$ddl = filter_input(INPUT_POST, 'ddl');
$rgp = filter_input(INPUT_POST, 'rgp');
$doit = filter_input(INPUT_POST, 'doit');
 
if (!is_null($doit)) {
  echo "reentrant";
}
else {
  echo "initial";
  // $rgp = "aa";    // initial preset
}
 
$data = [
    'entries' => $entries,
    'ddl' => $ddl,
    'rgp' => $rgp,
];
$smarty->assign($data);
$smarty->display("select.tpl");

templates/select.tpl
{extends file="layout.tpl"}
 
{block name="content"}
  <h2>Selection Form</h2>
  <form action="{$smarty.server.PHP_SELF}" method="post">
    <table class="table-condensed">
      <tr>
        <td>ddl:</td>
        <td>
          <select name="ddl">
            {html_options options=$entries selected=$ddl}
          </select>
        </td>
      </tr>
      <tr>
        <td>rgp:</td>
        <td class="radio">
          {html_radios name="rgp" options=$entries selected=$rgp}
        </td>
      </tr>
      <tr>
        <td></td>
        <td><button type="submit" name="doit">Submit</button></td>
      </tr>
    </table>
  </form>
{/block}

Smarty provides direct support for both selection lists and radio groups with dedicated, easy-to-use functions: html_options and html_radios. Smarty functions employ convenient named argument lists such as those found in the Python language in which there is no need to keep track of the argument position.

These functions create the selection elements from the options parameter ensure that the selections are sticky by usage of the selected parameter.

Single Checkbox

A single checkbox in a form represents a true/false value of something to be submitted; no particular value is selected. In this case, Smarty offers no special element, and so we code it directly by manipulating:
<input type='checkbox' name='cb' value='checked' {$cb} /> check me
To make the checkbox "checked" the value of $cb should be
$cb = "checked"
and so the value sent as the cb parameter, which is "checked" or nothing (null) can simply be sent back to the form for a reentrant call. Here is an example:

checkbox.php
<?php
require_once "include/smarty.php";
 
$entries = [ "aa"=>"Choice1", "bb"=>"Choice2", "cc"=>"Choice3", ];
 
//print_r($_POST);  // debug: see the parameters
 
$cbg = filter_input(INPUT_POST, 'cbg', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
 
$doit = filter_input(INPUT_POST, 'doit');
 
if (!is_null($doit)) {
  echo "reentrant";
}
else {
  echo "initial";
  // $cbg = ["aa","cc"]; // initial presets
}
 
$data = [
    'entries' => $entries,
    'cbg' => $cbg,
];
$smarty->assign($data);
$smarty->display("checkbox.tpl");

templates/checkbox.tpl
{extends file="layout.tpl"}
 
{block name="content"}
  <h2>Checkbox Group Form</h2>
  <form action="{$smarty.server.PHP_SELF}" method="post">
    <strong>cbg:</strong> 
    <p class="checkbox">
    {html_checkboxes name='cbg' options=$entries selected=$cbg
                     separator="<br />"
    }
    </p>
    <button type="submit" name="doit">Submit</button>
  </form>
{/block}

Multiple Selection Elements

Multiple selection elements deliver multiple occurrences of the same parameter with different values. The two form elements which generate such multiple occurrences can be regarded similarly: In both cases, zero or more choices can be made, yielding a parameter whose value is either undefined if nothing is chosen, or multi-valued. We can do arbitrary de-selections.

A feature of Php is that multi-valued parameter names must have the [] appended to it like this:
... param[]=value1&param[]=value2& ...
This means that all multi-valued parameters must use the [] suffix. If one or more choices are made, the corresponding Php parameter value is an array. If no choices are made the corresponding Php parameter value is unset, or null. One usually has to be careful to avoid using such parameter values in operations which request an array.

Checkbox Group Example

Smarty provides direct support for checkbox groups with a dedicated, easy-to-use function:
html_checkboxes
The checkbox name attribute is used directly as the name argument to this function without any need to add the brackets extension required in Pure Php.

templates/checkbox_group.tpl
{extends file="layout.tpl"}
 
{block name="content"}
  <h2>Checkbox Group</h2>
  <form action="{$smarty.server.PHP_SELF}" method="post">
    cbg:
    <p class="checkbox">
    {html_checkboxes name='cbg' options=$entries selected=$cbg}
    </p>
    <button type="submit" name="doit">Submit</button>
  </form>
{/block}
This template script illustrates an additional argument to this function, i.e., the separator argument. Its value represents the HTML code which is inserted between checkboxes. It this case the line break added makes the checkboxes present vertically.

checkbox_group.php
<?php
require_once "include/smarty.php";
 
//print_r($_POST);  // debug: see the parameters
 
$cbg = filter_input(INPUT_POST, 'cbg', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
 
$doit = filter_input(INPUT_POST, 'doit');
 
if (!is_null($doit)) {
  echo "reentrant";
}
else {
  echo "initial";
  // $cbg = ["aa","cc"]; // initial presets
}
 
$entries = [ "aa"=>"Choice1", "bb"=>"Choice2", "cc"=>"Choice3", ];
 
$data = [
    'entries' => $entries,
    'cbg' => $cbg,
];
$smarty->assign($data);
$smarty->display("checkbox_group.tpl");
As you see, the added complexity is in how the $cgb parameter is read. It is either null or is an array list of the selected values from the checkbox group. Our code indicates a way to generate presents within the checkbox group. The presets only take effect on an initial activation.


© Robert M. Kline