PX : code

Form Class by Jay Bloodworth
Download this code


<?php

/*

FORM 1.0a
Copyright 1998 by Jay Bloodworth

The following code provide's a nice class interface for (surprise)
html forms.  In particular, it provides a single interface for all
the form elements regardless of their syntax.  It also provides
simple client-side (javasript) and server-side validation, along
with a convenient way to fill in the form based on the last
submission (useful for error recovery).  The code, though not
commented, isn't THAT obscure, so this documentation will be
brief.

In general, you design a form by doing $formvar = new form and
then calling the the $formvar->add_element() function with a
single arg consisting of an associative array with appropriate
values (as given below) to define that type of element.  Most
of the form paramters are self explanatory, but a couple
deserve special comment:

options => This is an array of options presented with a
SELECT element.  It can either be an array of labels or
an array of associatives arrays of the form 
array("label"=>"Whatever You Want","value"=>"whatever")
If you choose the second form the label is what gets
displayed and value is what is submitted.

value => For SELECT items, this is the item that is
preselected.  It can be given as either the label or
value of the item.  For SELECT MULTIPLE items, it
can be an array.

valid_regex => For INPUT items of type text or password,
the submission will be checked against this regex for
validity.  Note that only the latest versions of 
Explorer and Navigator have a javascript engine that
supports regexes, so this test is meaningless for
older clients.  The server side validation can still
use it though.

valid_e => Message to be returned if the input is
invalid.  For text and password entries, this is
done with regexes as above.  For radio buttons,
the entry is invalid if no button in the set has
been selected.  For SELECT items, the submission
is invalid if the first item in the list is
selected; this is useful if you want the first
item in the list to be a label.  If you don't
want this behavior, just leave valid_e unset.

length_e => Message to be returned if a text or
password entry is less that min_l.

To start a form, call the method: 
$formvar->start($js,$method,$action)

This function takes from 0 to three arguments.  If
called without a $js argument, the form does not
provide a javascript validator.  The default method
is post and the default action is $PHP_SELF.

To display an element:
$formvar->show_element($name,$value)

Note that the value argument is required if and only
if the element is a radio button or a submit button,
since there can be multiple occurences of these
elements with the same name in a form.

To do server side validation, call:
$formvar->validate($default)

This returns the appropriate eeror message, or
$default if everything is okay.

To fill in the form with the last values submitted:
$formvar->load_defaults($varlist)

You probably want to wrap this in a conditional so
it is only called if you are receiving a submission.
$varlist is an optional array argument;  If present,
only the named elements will be affected.

A couple caveats:
You need to be using 3.0b6 or later and have
ignore_missing_userfunc_args set to on unless you
want to always use all the arguments to the methods.
If the action for the form is not $PHP_SELF, be sure
to declare the form and use the appropriate
add_element statements in the receiving page if you
want to use any of the form methods.  You probably
want to snipped these instructions before you use
this code on your server - no point in making the
server deal with them.  Don't forget to close your
form with the </form> tag (after all your
show_element calls).

This is far from perfect, but I hope it will be handy
to some people.  If upu've got ideas on how to improve
it and especially if you find obvious bugs, let me
know.

Share and enjoy.

Jay Bloodworth
jay@pathways.sde.state.sc.us

Legal Stuff:
Released under GNU Public License.  Absolutely,
positively, no exceptions, no way, no how, for
sure NO WARRANTY expressed or implied, not even
for fitness of purpose.

Form elements defined by: array("type"=>,
                "name"=>,
                "value"=>,
                "options"=>,
                "size"=>,
                "rows"=>,
                "cols"=>,
                "wrap"=>,
                "src"=>,
                "checked"=>,
                "min_l"=>,
                "max_l"=>,
                "extra_html"=>,
                "valid_regex"=>,
                "length_e"=>,
                "valid_e"=>)
*/

class form {

  var 
$elements;

  function 
load_defaults($deflist) {
    if (
$deflist) {
      
reset($deflist);
      
$el $this->elements[current($deflist)];
    } else {
      
reset($this->elements);
      
$el current($this->elements);
    }
    while (
$el) {
      if (!(
$eltype $el["type"])) {
    
$el current($el);
    
$eltype $el["type"];
      }
      
$elname $el["name"];
      global $
$elname;
      
$elval = $$elname;
      switch (
$eltype) {
      case 
"text":
      case 
"pass":
      case 
"textarea":
    
$this->elements[$elname]["value"] = $elval;
    break;
      case 
"checkbox":
    if (
$elval)
      
$this->elements[$elname]["checked"] = "yes";
    else
      
$this->elements[$elname]["checked"] = "no";
    break;
      case 
"radio":
    
reset ($this->elements[$elname]);
    while (
$temp current($this->elements[$elname])) {
      
$temp["checked"] = "no";
      
next($this->elements[$elname]);
    }
    
$this->elements[$elname][$elval]["checked"] = "yes";
    break;
      case 
"select":
      case 
"select multiple":
    
$this->elements[$elname]["value"] = $elval;
    break;
      }
      if (
$deflist) {
    
next($deflist);
    
$el $this->elements[current($deflist)];
      } else {
    
next($this->elements);
    
$el current($this->elements);
      }
    }
  }

  function 
start($jsv_name,$method,$action) {
    global 
$PHP_SELF;
    if (!
$method$method "POST";
    if (!
$action$action $PHP_SELF;
    if (
$jsv_name) {
      echo 
"<script language=\"javascript\">\n<!--\n";
      echo 
"function ${jsv_name}_Validator(f) {\n";
      
reset($this->elements);
      while (
$el current($this->elements)) {
    if (!
$el["type"])
      
$el current($el);
    
$elname $el["name"];
    
$eltype $el["type"];
    switch (
$eltype) {
    case 
"text":
    case 
"password":
      
$el_e $el["length_e"];
      if (
$elmin $el["min_l"]) {
        echo 
"if (f.${elname}.value.length < $elmin) {\n";
        echo 
"alert(\"$el_e\");\n";
        echo 
"f.${elname}.focus();\n";
        echo 
"return(false);\n}\n";
      }
      if (
$el_e $el["valid_e"]) {
        
$el_re $el["valid_regex"];
        echo (
"if (window.RegExp) {\n");
        echo 
"var reg = new RegExp(\"$el_re\");\n";
        echo 
"if (!reg.test(f.${elname}.value)) {\n";
        echo 
"alert(\"$el_e\");\n";
        echo 
"f.${elname}.focus();\n";
        echo 
"return(false);\n";
        echo 
"}\n}\n";
      }
      break;
    case 
"radio":
      if (
$el_e $el["valid_e"]) {
        echo 
"var l = f.${elname}.length;\n";
        echo 
"var radioOK = false;\n";
        echo 
"for (i=0; i<l; i++)\n";
        echo 
"if (f.${elname}[i].checked) {\n";
        echo 
"radioOK = true;\n";
        echo 
"break;\n";
        echo 
"}\n";
        echo 
"if (!radioOK) {\n";
        echo 
"alert(\"$el_e\");\n";
        echo 
"return(false);\n";
        echo 
"}\n";
      }
      break;
    case 
"select":
      if (
$el_e $el["valid_e"]) {
        echo 
"if (f.${elname}.selectedIndex == 0) {\n";
        echo 
"alert(\"$el_e\");\n";
        echo 
"f.${elname}.focus();\n";
        echo 
"return(false);\n";
        echo 
"}\n";
      }
      break;
    }
    
next($this->elements);
      }
      echo 
"}\n//-->\n</script>\n";
      echo 
"<form method=\"$method\" ";
      echo 
"action=\"$action\" ";
      echo 
"onsubmit=\"return ${jsv_name}_Validator(this)\">\n";
    }
    else echo 
"<form method=\"$method\" action=\"$action\">";
  }

  function 
validate($default) {
    
reset($this->elements);
    while (
$el current($this->elements)) {
      if (!
$el["type"])
    
$el current($el);
      
$elname $el["name"];
      
$eltype $el["type"];
      global $
$elname;
      
$elval = $$elname;
      switch (
$eltype) {
      case 
"text":
      case 
"password":
    
$el_e $el["length_e"];
    if ((
$elmin $el["min_l"]) && strlen($elval) < $elmin)
      return 
$el_e;
    
$elreg $el["valid_regex"];
    if ((
$el_e $el["valid_e"]) && !ereg($elreg,$elval))
      return 
$el_e;
    break;
      case 
"radio":
    if ((
$el_e $el["valid_e"]) && !$elval)
      return 
$el_e;
    break;
      case 
"select":
    if (
$el_e $el["valid_e"]) {
      
$elops $el["options"];
      
reset($elops);
      
$elops current($elops);
      if (
is_array($elops))
        
$elops $elops["value"];
      if (
$elval == $elops)
        return 
$el_e;
    }
    break;
      }
      
next($this->elements);
    }
    return(
$default);
  }

  function 
add_element($el) {
    if ((
$el["type"] != "radio") && ($el["type"] != "submit"))
      
$this->elements[$el["name"]] = $el;
    else
      
$this->elements[$el["name"]][$el["value"]] = $el;
  }

  function 
show_element($name,$value) {
    if (
$value)
      
$el $this->elements[$name][$value];
    else
      
$el $this->elements[$name];
    
$eltype $el["type"];
    
$elname $el["name"];
    
$elvalue $el["value"];
    
$elextrahtml $el["extra_html"];
    switch (
$eltype) {
    case 
"text":
    case 
"password":
      echo 
"<input type=\"$eltype\" name=\"$elname\" value=\"$elvalue\"";
      if (
$el["max_l"]) {
    
$elmaxl $el["max_l"];
    echo 
"maxlength=\"$elmaxl\"";
      }
      if (
$el["size"]) {
    echo 
"size=\"$size\"";
    
$elsize $el["size"];
      }
      echo 
"$elextrahtml>\n";
      break;
    case 
"image":
      echo 
"<input type=\"$eltype\" name=\"$elname\" value=\"$elvalue\"";
      
$elsrc $el["src"];
      echo 
"src=\"$elsrc\" $elextrahtml>\n";
      break;
    case 
"checkbox":
    case 
"radio":
      if ((
$elchk $el["checked"]) && $elchk != "no")
    
$elextrahtml .= " checked";
    case 
"hidden":
    case 
"submit":
    case 
"reset":
      echo 
"<input type=\"$eltype\" name=\"$elname\" value=\"$elvalue\"";
      echo 
"$elextrahtml>\n";
      break;
    case 
"textarea":
      
$elrows $el["rows"];
      
$elcols $el["cols"];
      
$elwrap $el["wrap"];
      echo 
"<textarea name=\"$elname\" ";
      echo 
"rows=\"$elrows\" cols=\"$elcols\" wrap=\"$elwrap\"";
      echo 
"$elextrahtml>\n";
      echo 
"$elvalue";
      echo 
"</textarea>";
      break;
    case 
"select":
    case 
"select multiple":
      
$elsize $el["size"];
      
$elops $el["options"];
      echo 
"<$eltype name=\"$elname";
      if (
$eltype == "select multiple")
    echo 
"[]\"";
      else
    echo 
"\"";
      if (
$elsize)
    echo 
" size=\"$elsize\"";
      echo 
"$elextrahtml>\n";
      while (
$curop current($elops)) {
    echo 
"<option";
    if (
is_array($curop)) {
      
$curval $curop["value"];
      
$curop $curop["label"];
      echo 
" value=\"$curval\"";
    }
    if (
is_array($elvalue)) {
      
reset($elvalue);
      while (
$temp current($elvalue)) {
        if (
$temp == $curval || $temp == $curop)
          echo 
" selected";
        
next($elvalue);
      }
    } elseif (
$elvalue == $curval || $elvalue == $curop
      echo 
" selected";
    echo 
">$curop</option>\n";
    
next($elops);
      }
      echo 
"</select>\n";
      break;
     
    }
  }

}

?>

Comments or questions?
PX is running PHP 5.2.17
Thanks to Miranda Productions for hosting and bandwidth.
Use of any code from PX is at your own risk.