PX : code

Form Class by Jay Bloodworth
Download this code


<?php

/*

Form 1.1 
Copyright 1998 by Jay Bloodworth
Released under GNU Public License v2.0, available at www.fsf.org
Most important part of license:
This software is provided with NO WARRANTY.  None. Zilch.  Not even an 
implied warranty for fitness of purpose.

The following PHP3 code provides a nice class interface for html
forms.  In particular, it provides a single, reasonably consistent
interface for all form elements regardless of the html syntax.  It
tries to do the right thing with all 'reasonable' (IMHO) variations on 
input syntax.  The interface also provides a regexp base validation
function for the server side, along with javascript validation (for
versions of jscript that support regexps) on the client side.  There
is also a function to load any or all the fields of a defined for with 
defaults based on GET or POST data.

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.  Note
also that the regex is actually checked to see if it occurs anywhere in
the input as a subexpression (I declare this a feature, not a bug).  If
you want the regex to match the whole string, put it between ^ and $.
E.G. [0-9]+ will match 'abc123def', which may not be what you want.  If
you want to accept just digits, use $[0-9]+

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 show form elements, you usually use
$formvar->show_element("element_name"), but in the case of radio
buttions and submit buttons you use
$formvar->show_element("element_name","element_value") since you may
have multiple elements with the same name.

To close the form, use $myform->finish().  Not only will this output
the </form> tag, it will output any elements of type "hidden" you
defined, so there is no need to call show_element for these.

The $myform->validate function takes one mandatory and one optional
argument.  This function will return the defined error message if one
the form elements doesn't meet it's validation requirements, or it's
first argument (usually a string) if everthing checks out.  The
optional second argument is a list of names of form elements to
perform validation on; all others will be ignored (without this, all
elements will be checked).

The $myform->load_defaults function will load the form elements with
default values based on variables that have the same name as the form
elements; this function is intended to be used to recycle previous
input to the form so the user won't have to enter everything again if
he or she makes one mistake.  The function takes one optional
argument, a list of names of form elements.  As above, if this
argument is given, only these elements will be affected; otherwise all 
of them will.


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"=>,
*/

// This function is needed because unset is current (3.0b6) buggy
// when used for associative arrays.
function myunset($a,$key) {

  
reset($a);
  while (
$i current($a)) {
   if (
$key != ($k key($a)))
     
$t[$k] = $i;
   
next($a);
  }

  
$a=$t;
}

class 
form {

  var 
$elements;
  var 
$hidden;

  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 (isset(
$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;
    
$elops $this->elements[$elname]["options"];
    if (
is_array($elops)) {
      
reset($elops);
      
$elops current($elops);
      if (isset(
$this->elements[$elname]["valid_e"]) &&  
          !((
is_array($elops) && (($elops["label"] == $elval) ||
                      (
$elops["value"] == $elval))) ||
        (
$elops == $elval))) {
        
myunset(&$this->elements[$elname]["options"],0);
        unset(
$this->elements[$elname]["valid_e"]);
      }
    }
    break;
      }
      if (
$deflist) {
    
next($deflist);
    
$el $this->elements[current($deflist)];
      } else {
    
next($this->elements);
    
$el current($this->elements);
      }
    }
  }

  function 
start($jsv_name="",$method="",$action="",$target="") {
    global 
$PHP_SELF;
    if (!
$method$method "POST";
    if (!
$action$action $PHP_SELF;
    if (!
$target$target "_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 
"target=\"$target\" ";
      echo 
"onsubmit=\"return ${jsv_name}_Validator(this)\">\n";
    }
    else
      echo 
"<form method=\"$method\" action=\"$action\" target=\"$target\">";
  }

  function 
finish() {
    if (
$this->hidden) {
      
reset($this->hidden);
      while (
$elname current($this->hidden)) {
    
$elval $this->elements[$elname]["value"];
    echo 
"<input type=\"hidden\" name=\"$elname\" value=\"$elval\">\n";
    
next($this->hidden);
      }
    }
    echo 
"</form>\n";
  }

  function 
validate($default,$vallist="") {
    if (
$vallist) {
      
reset($vallist);
      
$el $this->elements[current($vallist)];
    } else {
      
reset($this->elements);
      
$el current($this->elements);
    }
    while (
$el) {
      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;
      }
      if (
$vallist) {
    
next($vallist);
    
$el $this->elements[current($vallist)];
      } else {
    
next($this->elements);
    
$el current($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;
    if (
$el["type"] == "hidden")
      
$this->hidden[] = $el["name"];
  }

  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 (
$elsize $el["size"])
    echo 
" size=\"$elsize\"";
      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";
      if (
is_array($elops))
    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 ((isset(
$curval) && ($elvalue == $curval)) 
            || 
strval($elvalue) == strval($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.