Home    Files

software times™  Files...

July 26, 2011

Web Form Script Architecture


Screen Shots of a Form Web App

The images are not to scale.

The script starts by asking for Username and Password
Form 1
What happens next depends on the user's input. If the input is invalid the user gets an error messageForm 2
If the input is valid the user gets a working form, in this case a list of options and action buttonsForm 3
In this example, if the user clicks on an Edit button, he'll get the corresponding edit formForm 4
If the input is not valid, the user gets the same form with the corresponding error messagesForm 5
If the input is valid, the user gets to review his input before submitting itForm 6
If on submitting the form everything goes off without a hitch, the user gets confirming feedback and the page to start a new edit, completing the cycleForm 7
The process can become interrupted if somethng goes wrong with security, for example, the session timing outForm 8
Organizing the Script
<?php
/* housekeeping */

// functions

/* start security */

session_start();
// initialize variables
// check for session cookie (SID)
// set $action

switch ($action)  {

  case "Logout":
      // destroy session
      
  case "Enter":
      // verify password

/* start business logic */
case "Review": // validate input case "Edit": // get data from database case "New entry": // prepare empty form case "Submit": // prepare data for emaling } // switch ($action)
/* start presentation */

?>
<!doctype html>
HTML top
<?php
switch ($action)  {

  case "No cookie":
      // abort
      
  case "Logout":
      // logout

  case "": // first entry
      // password form
      
  case "Submit":
      // send email

  case "Enter":
      // List directory and businesses
      
  case "Edit":
  case "New entry":
      // Edit form

  case "Review":
      // Review form
      
  case "Enter":
      // verify password
      
} // switch ($action)

?>
HTML foot

Web form scripts are complex and they tend to be daunting for new programmers but they need not be once you understand what is involved in such a script and organize the bits and pieces in a meaningful way.

A Conversation

Think of the script as a conversation between a machine and a human. The sidebar shows a series of screen shots of my latest form script. The script lets as human editor enter new businesses into a directory or edit existing ones. Since this is a password protected script, it starts by presenting a form requesting the editor's Username and Password. Once the editor's ID is established, the script shows all the directory entries and lets the editor pick a business to edit or to request an empty form to include a new business. The editor enters the data, the script does some validation and either reports errors or shows the new or edited listing. At this point the editor can either continue editing the entry or submit the data for inclusion in the database. On submission, the script sends me an email and gives the editor feedback about the action taken or it reports any errors. There are a couple more options: the editor can log out of the script or the script can detect that the session has timed out. In each case, the editor receives the corresponding feedback.

Please take a moment to familiarize yourself with the screen shots in the sidebar.

The script's execution is circular. Each time it is called it determines where in the process it is and responds accordingly. I have found that it is easiest if a single script file controls the process. That does not mean that all the code has to be in a single file, the controlling script can include other files or call functions in other files. How exactly to organize the includes and the helper functions is a matter of choice. Simple forms I prefer to keep inline while complex ones I prefer to include from a separate file. Experience will guide you in making this choice.

Business Logic, Presentation & Security

php allows you to jump back and forth between HTML and php. The danger is that if you are not careful, you are likely to wind up with what is generally known as "spaghetti code." To make sure this does not happen, the script will be clearly divided into three parts. The usual suggestion is to keep the business logic separate from the presentation, in this case the HTML that is sent to the browser. I add a third part, what might be called the script's security code since this is neither business logic nor presentation proper.

Sessions, YES! Captchas, NO!

I find it highly desirable to use sessions and session cookies to implement the script's security. HTTP is generally a stateless protocol and if you want to prevent things like sending two emails by hitting the Submit button twice or hitting the back button to send the form again, you need the script to be stateful which is achieved with sessions.

Captchas have become popular as a security measure to defeat robots but they are an absolutely horrendous idea. Your script is supposed to be user friendly and captchas are everything but. Just because you want to defeat robots is not a good reason to make legitimate users jump through annoying hoops. My session based contact scripts have been defeating robots for over eight years. There was only one case where I was not sure if the input (email) came from a robot or from a user typing nonsense. If there is no password protection as is the case with contact forms, robots are quite capable of filling in the form and submitting it.

My scripts have an intermediate step where the user verifies the input before sending it. This intermediate step stops the robots I suppose because they don't accept cookies. Even if they did, they would still have to know which button to use to send the form. Using JavaScript you can build additional robot detection code that is transparent to the user. I have not found a need for this addtional protection. To sum up, the use of captchas is a sign of crappy user interface design.

Organizing the Script

I use two large switch() constructs to organize the code. After any housekeeping code you might have, the Security section starts with a session_start() statement followed by initializing variables and setting the switch() construct variable $action with data from the $_POST or $_GET global variables.

The first switch() encompasses both the Security section and the Business Logic. The Security section might consist of two cases, one to validate the user and a second to log out. If you are doing fancy security checks, like checking for the use of the back button, you can add more cases as needed.

Controlling the Second Switch()

One useful feature of the switch() construct is that once you enter it, you can change the value of the switch() expression with no effect on the currently running switch(). This means that in the first switch you can change the value of this variable to control the execution of the presentation switch(). Of course, you could always use two diffrent variables instead. wink

The Presentation is essentially the HTML that is sent to the browser. Embedded in the HTML is a second switch() where each case dispays a particular form or feedback.

The illustration in the sidebar shows the various parts in pseudo-code.

Closing Thoughts

If at all possible, use HTML5 which has some great new features for HTML forms such as the "placeholder" attribute and new input types such as "email" and "url."

Use arrays for managing data. The HTML forms send the input data via the associative arrays $_POST or $_GET using the input fields' name attribute as the keys. Instead of going to the trouble of extracting the values to simple variables, keep them together in your own arrays. For example, you could use a simple assigment to transfer the $_POST data to your own array:
  <?php
  $input = $_POST;
  ?>
If you need to strip slashes you can use the following function to loop through the array:
  function arrayStripSlashes (&$data) {
  
      if (!is_array($data)) { return FALSE; }
      $result = array();
      foreach ($data AS $key=>$value) {
          $result[$key] = stripslashes ($value);
      }
      return $result;
  
  }
Should you be using checkboxes or selects with multiple results, some input values will be arrays and the above function needs to be converted to a recursive version.

As I mentioned above, if the forms are large it makes sense to put them in separate include files. If they are small, I prefer to define them inline using heredoc string syntax, for example:
  echo <<<DATADATA
  <form action="{$_SERVER['PHP_SELF']}" method="post">
  <fieldset style="width:350px;">
  <legend>Permision to edit the directory</legend>
    <div class="table">
      <div class="row">
        <div class="cell" style="width:80px;">Username: </div>
        <div class="cell"><input style="margin-left100px;" type="text"
            name="name" value="" size="40" maxlength="15"></div>
      </div>
      <div class="row">
        <div class="cell">Email: </div>
        <div class="cell"><input style="margin-left100px;" type="email"
            name="email" value="" size="40" maxlength="63">{$feedback}</div>
      </div>
      <div class="row">
        <div class="cell"></div>
        <div class="cell"><input type="submit" name="action" value="Enter">
          <input type="reset" name="" value="Reset"></div>
      </div>
    </div>
  </fieldset>
  </form>
  
  DATADATA;
Note that in line two above, in the form tag, there is an embedded system variable "{$_SERVER['PHP_SELF']}" using the "complex (curly) syntax" and another php variable "{$feedback}" further down:
Complex (curly) syntax
This isn't called complex because the syntax is complex, but because it allows for the use of complex expressions.
In fact, any value in the namespace can be included in a string with this syntax. Simply write the expression the same way as it would have appeared outside the string, and then wrap it in { and }. Since { can not be escaped, this syntax will only be recognised when the $ immediately follows the {. Use {\$ to get a literal {$.
Since I'm using associative arrays for the data, the complex (curly) syntax is the easiest way to include them in php strings. Just get used to using curly brackets {} all the time.

As a final note, Apple and Mac and now the iSeries consumer electronic products owe much of their success to the Apple Human Interface Guidelines (now renamed "Mac OS X Human Interface Guidelines") which Apple has been developing since 1984. Web-apps can benefit greatly from Apple's accumulated experience which, fortunately, Apple is happy to share. You can get the document online for free. See the link below.

Denny Schlesinger


php strings
Mac OS X Human Interface Guidelines


Home    Files
Top
Copyright © Software Times, 2000, 2001, 2003. All rights reserved
Last updated March 8, 2009.