<?php
/*
* Form class by Jonas Delfs
*
* Feel free to use and be inspired, but do not
* redistribute under another name than mine
*
* @version 0.9.1
*/

class Form {
    
    var 
$formAttr = array();
    var 
$tabOffset 0;
    var 
$tableAttr = array();
    var 
$elements = array();
    var 
$values = array();
    var 
$submitVars = array();
    var 
$errors = array();
    var 
$reservedKeys = array('label''element''validate''errmsg''elements');
    var 
$stdErrMsg "Field is required.";
    var 
$stdErrMsgUnequal "Field must be equal to the other.";
    var 
$showRequired true;
    var 
$matches = array('number' => array('regex' => '/^\d+$/''errmsg' => 'Field must be a number.'),
                         
'float' => array('regex' => '/^[0-9]+\.[0-9]+$/''errmsg' => 'Field must be a float.'),
                         
'letters' => array('regex' => '/^[a-zæøå]+$/i''errmsg' => 'Field must be letters'),
                         
'word' => array('regex' => '/^\w+$/i''errmsg' => 'Field must be word characters.'),
                         
'words' => array('regex' => '/^[\w\s]+$/i''errmsg' => 'Field must be word characters and space.'),
                         
'email' => array('regex' => '/^([\w|\.|\-|_]+)@([\w||\-|_]+)\.([\w|\.|\-|_]+)$/i''errmsg' => 'Field must be a valid email-adress'));
    
    function 
Form($formAttr=NULL$tabOffset=0$tableAttr=NULL$elements=NULL)
    {
        
$this->formAttr = (array)$formAttr;
        
$this->tabOffset = (int)$tabOffset;
        
$this->tableAttr = (array)$tableAttr;
        
$this->submitVars = (array)array_merge($_GET$_POST);
        
$this->elements = (array)$elements;
        
        if (!isset(
$this->formAttr['name'])) {
            if (
$this->submitVars['__FORMID__']) {
                
$this->formAttr['name'] = $this->submitVars['__FORMID__'];
            } else {
                
mt_srand ((double)microtime() * 1000000);
                
$this->formAttr['name'] = md5(crypt(mt_rand(1mt_getrandmax())));
            }
        }
    }
    
    function 
reset() {
        
$this->submitVars = array();
    }
    
    function 
_getAttrString($attributes)
    {
        
$strAttr '';
        if (
is_array($attributes)) {
            foreach(
$attributes AS $key => $value) {
                if (
is_int($key)) {
                    
$strAttr .= ' '.strtolower($value).'="'.$value.'"';
                } else {
                    
$strAttr .= ' '.strtolower($key).'="'.$value.'"';
                }
            }
        }
        return 
$strAttr;
    }
    
    function 
_getIndent()
    {
        return 
$this->tabOffset str_repeat("\t"$this->tabOffset) : '';
    }
    
    function 
_insertVars(&$vars)
    {
        
$checked = array();
        for(
$i=0$i count($this->elements); $i++) {
            if (
is_array($this->elements[$i]['elements'])) {
                for(
$index=0$index count($this->elements[$i]['elements']); $index++) {
                    
$this->_insertVar($vars$this->elements[$i]['elements'][$index], $checked);
                }
            } else {
                
$this->_insertVar($vars$this->elements[$i], $checked);
            }
        }
    }
    
    function 
_insertVar(&$vars, &$element, &$checked)
    {
        if (
$element['type'] == 'radio') {
            if (
$vars[$element['name']] == $element['value']) {
                
$element['checked'] = 'checked';
                
$checked[$element['name']] = true;
            } else {
                for(
$index=0$index count($element); $index++) {
                    if (
$element[$index] == 'checked') {
                        unset(
$element[$index]);
                    }
                }
            }
        } elseif (
$element['type'] == 'select') {
            foreach(
$element['value'] AS $key => $val) {
                
//echo "'".$val."': '".$vars[$element['name']]."'<br/>\n";
                //echo "'".$val['value']."': '".$vars[$element['name']]."'<br/>\n";
                
if (($val == $vars[$element['name']]
                        || (
is_array($val) && $val['value'] == $vars[$element['name']])
                        || (
is_string($val)
                            && 
is_array($vars[$element['name']])
                            && 
in_array($val$vars[$element['name']]))
                        || (
is_string($val['value'])
                            && 
is_array($vars[$element['name']])
                            && 
in_array($val['value'], $vars[$element['name']])))
                    && ((
is_array($element['value'][$key])
                        && !
in_array('selected'$element['value'][$key]))
                        || (
is_string($element['value'][$key])
                        && 
$element['value'][$key] != 'selected'))) {
                    
                    if (
is_array($element['value'][$key])) {
                        
$element['value'][$key]['selected'] = 'selected';
                    } else {
                        
//echo "'".$element['value'][$key]."'";
                        
$element['value'][$key] = array('value' => $element['value'][$key], 'selected' => 'selected');
                    }
                } else {
                    if (
is_array($element['value'][$key])) {
                        foreach(
$element['value'][$key] AS $index => $_) {
                            if (
$element['value'][$key][$index] == 'selected') {
                                unset(
$element['value'][$key][$index]);
                            }
                        }
                    }
                }
            }
        } elseif (
substr($element['name'], -2) == '[]') {
            if (!
$arrayFields[$element['name']]) {
                
$arrayFields[$element['name']] = 0;
            }
            if (
is_array($vars[substr($element['name'], 0, -2)])) {
                
$element['value'] = $vars[substr($element['name'], 0, -2)][$arrayFields[$element['name']]];
            }
            
$arrayFields[$element['name']]++;
        } else {
            if (
$vars[$element['name']]) {
                
$element['value'] = $vars[$element['name']];
            }
        }
    }
    
    function 
insertValue($mixed$value=NULL)
    {
        if (!
is_array($mixed)) {
            
$mixed = array($mixed => $value);
        }
        
//$this->values = array_merge($this->values, $mixed);
        
$this->_insertVars($mixed);
    }
    
    function 
getSubmitted($name=NULL)
    {
        if (
$name) {
            return 
$this->submitVars[$name];
        } elseif (
gettype($name) != NULL) {
            return 
false;
        }
        return 
$this->submitVars;
    }
    
    function 
isSubmitted()
    {
        if (
$this->submitVars['__FORMID__'] == $this->formAttr['name']) {
            return 
true;
        }
        return 
false;
    }
    
    function 
addElement($mixed$type=NULL$name=NULL$value=NULL$attr=NULL$validate=NULL$errmsg=NULL)
    {
        
$this->elements[] = $this->getElement($mixed$type$name$value$attr$validate$errmsg);
    }
    
    function 
addElementGroup($mixed$elements)
    {
        
$this->elements[] = $this->getElementGroup($mixed$elements);
    }
    
    function 
getElement($mixed$type=NULL$name=NULL$value=NULL$attr=NULL$validate=NULL$errmsg=NULL)
    {
        if (!
is_array($mixed)) {
            
$mixed = array('label' => $mixed'type' => $type'name' => $name'value' => $value'validate' => $validate'errmsg' => $errmsg);
            
$mixed array_merge($attr$mixed);
            if (
$mixed['validate'] && !$mixed['errmsg']) {
                for(
$i=0$i count($this->matches); $i++) {
                    if (
$mixed['validate'] == $this->matches[$i]['regex']) {
                        
$mixed['errmsg'] = $this->matches[$i]['errmsg'];
                    }
                }
            }
            if (
$mixed['validate'] && !$mixed['errmsg']) {
                
$mixed['errmsg'] = $this->stdErrMsg;
            }
        }
        return 
$mixed;
    }
    
    function 
getElementGroup($mixed$elements)
    {
        if (!
is_array($mixed)) {
            
$mixed = array('label' => $mixed'elements' => $elements);
        }
        
$mixed['type'] = 'group';
        return 
$mixed;
    }
    
    function 
buildElement($mixed$name=NULL$value=NULL$attr=NULL)
    {
        if (!
is_array($mixed)) {
            
$attributes = array('type' => $mixed'name' => $name'value' => $value);
            
$mixed array_merge($attr$attributes);
        }
        if (isset(
$mixed['element'])) {
            return 
$mixed['element'];
        }
        foreach(
$mixed AS $key => $val) {
            if (
in_array((string)$key$this->reservedKeys)) {
                unset(
$mixed[$key]);
            }
        }
        
$indent $this->_getIndent();
        switch(
$mixed['type']) {
            
            case 
'select':
                
$options $mixed['value'];
                unset(
$mixed['value']);
                
$strHtml  "<select".$this->_getAttrString($mixed).">\n";
                foreach(
$options AS $k => $v) {
                    
$strHtml .= $indent."            <option";
                    if (
is_array($v)) {
                        
$strHtml .= $this->_getAttrString($v);
                    } else {
                        
$strHtml .= " value=\"".$v."\"";
                    }
                    
$strHtml .= ">";
                    
$strHtml .= is_string($k) ? $k : (is_string($v) ? $v $v['value']);
                    
$strHtml .= "</option>\n";
                }
                
$strHtml .= $indent."        </select>";
                break;
                
            case 
'textarea':
                
$value $mixed['value'];
                unset(
$mixed['value']);
                
$strHtml "<textarea".$this->_getAttrString($mixed).">".$value."</textarea>";
                break;
                
            default:
                if (!isset(
$mixed['value'])) {
                    unset(
$mixed['value']);
                }
                
$strHtml "<input".$this->_getAttrString($mixed).">";
                break;        
        }
        
        return 
$strHtml;
    }
    
    function 
buildElementGroup($element)
    {
        
$indent $this->_getIndent();
        
$strHtml '';
        for(
$i=0$i count($element); $i++) {
            if (
$placeBefore) {
                
$strHtml .= ' '.$element[$i]['label'].' ';
            }
            
/*if ($element[$i]['type'] == 'radio'
                && $element[$i]['value'] == $this->values[$element[$i]['name']]) {
                $element[$i]['checked'] = 'checked';
            }*/
            
$strHtml .= $this->buildElement($element[$i])."\n";
            if (!
$placeBefore) {
                
$strHtml .= ' '.$element[$i]['label'].' ';
            }
            
$strHtml .= $indent."\t\t";
        }
        return 
$strHtml;
    }
    
    function 
_getErrmsg($element)
    {
        if (
$element['errmsg']) {
            
$errmsg $element['errmsg'];
        } elseif (
$this->matches[$element['validate']]['errmsg']) {
            
$errmsg $this->matches[$element['validate']]['errmsg'];
        } elseif (
$this->getSubmitted($element['validate'])) {
            
$errmsg $this->stdErrMsgUnequal;
        } else {
            
$errmsg $this->stdErrMsg;
        }
        return 
$errmsg;
    }
    
    function 
_setInsertedValue(&$element)
    {
        if (isset(
$this->values[$element['name']])
            && 
$element['type'] != 'radio'
            
&& $element['type'] != 'select') {
            
            
$element['value'] = $this->values[$element['name']];
        }
    }
    
    function 
toHtml()
    {
        
/*for($i=0; $i < count($this->elements); $i++) {
            if (is_array($this->elements[$i]['elements'])) {
                for($index=0; $index < count($this->elements[$i]['elements']); $index++) {
                    $this->_setInsertedValue($this->elements[$i][$index]);
                }
            } else {
                $this->_setInsertedValue($this->elements[$i]);
            }
        }*/
        
if ($this->isSubmitted()) {
            
$this->_insertVars($this->submitVars);
        }
        
$indent $this->_getIndent();
        
$strHtml  $indent."<form".$this->_getAttrString($this->formAttr).">\n";
        
$strHtml .= $indent.$this->buildElement('hidden''__FORMID__'$this->formAttr['name'])."\n";
        
$strHtml .= $indent."<table".$this->_getAttrString($this->tableAttr).">\n";
        foreach(
$this->elements AS $element) {
            if (
$element['type'] == 'hidden') {
                
$strHtml .= $indent.$this->buildElement($element);
            } else {
                
$strHtml .= $indent."    <tr>\n";
                if (
$this->showRequired) {
                    
$strHtml .= $indent."        <td valign=\"top\">";
                    if (isset(
$element['validate'])) {
                        
$strHtml .= "*";
                    }
                    
$strHtml .= "</td>\n";
                }
                
$strHtml .= $indent."        <td";
                if (
$element['type'] == 'textarea'
                    
|| ($element['type'] == 'select' && ($element['size'] > || in_array('multiple'$element)))
                    || 
$this->errors[$element['name']]) {
                    
                    
$strHtml .= " valign=\"top\"";
                }
                
$strHtml .= ">".$element['label']."</td>\n";
                
$strHtml .= $indent."        <td>";
                if (
$element['type'] == 'group') {
                    
$strHtml .= $this->buildElementGroup($element['elements']);
                } else {
                    
$strHtml .= $this->buildElement($element);
                }
                if (
$this->errors[$element['name']]) {
                    
$strHtml .= "<br/>\n";
                    
$strHtml .= $indent."\t\t\t<span style='color:#FF0000;'>".$this->errors[$element['name']]."</span>";
                }
                
$strHtml .= "</td>\n";
                
$strHtml .= $indent."    </tr>\n";
            }
        }
        
$strHtml .= $indent."</table>\n";
        
$strHtml .= $indent."</form>";
        
        return 
$strHtml;
    }
    
    function 
display()
    {
        echo 
$this->toHtml();
    }
    
    function 
validate()
    {
        if (!
$this->isSubmitted()) {
            return 
false;
        }
        
$return 1;
        foreach(
$this->elements AS $element) {
            if (
is_array($element['elements'])) {
                foreach(
$element['elements'] AS $element) {
                    
$this->_validateElement($element$return);
                }
            } else {
                
$this->_validateElement($element$return);
            }
        }
        return (
$return false true);
    }
    
    function 
_validateElement($element, &$return)
    {
        if ((
substr($element['validate'], 01) == '/'
                
&& !preg_match($element['validate'], $this->getSubmitted($element['name'])))
            || (
$element['validate'] == 'required'
                
&& !$this->getSubmitted($element['name']))
            || (
$this->matches[$element['validate']]
                && !
preg_match($this->matches[$element['validate']]['regex'], $this->getSubmitted($element['name'])))
            || (
$this->getSubmitted($element['name'])
                && 
$this->getSubmitted($element['validate'])
                && 
$this->getSubmitted($element['name']) != $this->getSubmitted($element['validate']))) {
            
$return--;
            
$this->errors[$element['name']] = $this->_getErrmsg($element);
        }
    }
    
    function 
getJs() {
        
$name $this->formAttr['name'];
        
        
$this->formAttr['onsubmit'] = "return eval".$name."();";
        
        
$indent $this->_getIndent();
        
        
$js  $indent."<SCRIPT LANGUAGE='JavaScript' TYPE='text/javascript'>\n";
        
$js .= $indent."<!--\n";
        
        
$js .= $indent."function eval".$name."() {\n";
        
$js .= $indent."    \n";
        
$js .= $indent."    var thisForm = document.forms['".$name."'];\n";
        
        
$js .= $indent."    var requiredFields = new Array(";
        for(
$i=0$i count($this->elements); $i++) {
            if (isset(
$this->elements[$i]['validate'])) {
                if (
$count) {
                    
$js .= ", ";
                }
                
$js .= "\n".$indent."        new Array(\"".$this->elements[$i]['name']."\", \"".$this->elements[$i]['label']."\", \"".$this->_getErrmsg($this->elements[$i])."\")";
                
$count++;
            }
        }
        
$js .= $indent."        );\n";
        
$js .= $indent."    for (var i = 0; i < requiredFields.length; i++) {\n";
        
$js .= $indent."        if (thisForm.elements[requiredFields[i][0]].value == \"\") {\n";
        
$js .= $indent."            alert(requiredFields[i][1] + \": \" + requiredFields[i][2])\n";
        
$js .= $indent."            thisForm.elements[requiredFields[i][0]].focus();\n";
        
$js .= $indent."            return false;\n";
        
$js .= $indent."        }\n";
        
$js .= $indent."    }\n";
        
$js .= $indent."}\n";
        
$js .= $indent."//-->\n";
        
$js .= $indent."</SCRIPT>\n";
    
        return 
$js;
    }
    
    function 
isValid($mixed$required)
    {
        if (
is_string($mixed)) {
            
$mixed $GLOBALS['HTTP_'.strtoupper($mixed).'_VARS'];
        }
        foreach(
$required AS $field) {
            if (!isset(
$mixed[$field])) {
                return 
false;
            }
        }
        return 
true;
    }
}
?>