<?php
/*
PHP Form Processor - Helps simplify the process of building and processing forms in PHP
Version 2.01 - 21/01/2009
Copyright (C) <2009> <Richard Willars>
Additional scripting provided by Andrew Dunn.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
Any queries can be directed to Richard at www.richardwillars.com/contact/
*/
class FormProcessor {
public $formml;
public $formxml;
private $count = 1;
private $rules = array();
private $elements = array();
private $callbacks = 0;
private $errors = array();
private $randomkey1 = '';
private $randomkey2 = '';
private $config = array();
private function displayChildrenRecursive($xmlObj,$depth=0) {
foreach($xmlObj->children() as $obj) {
if ($obj->getName()=='element') {
$props = array();
foreach ($obj as $prop => $prop2) {
$props[] = $prop;
}
$formels = array('input','select','textarea');
$type = '';
foreach ($formels as $formel) {
if (in_array($formel, $props)) {
$type = $formel;
break;
}
}
if (strlen($type)!=0) {
switch ($type) {
case 'input':
if (isset($obj->attributes()->id)) {
$this->count++;
//Extract the rules
$this->rules["{$obj->attributes()->id}"] = array();
$this->rules["{$obj->attributes()->id}"]['type'] = (string)$obj->input->attributes()->type;
$this->callbacks = 0;
if (($this->rules["{$obj->attributes()->id}"]['type']=='text') || ($this->rules["{$obj->attributes()->id}"]['type']=='password')) {
if (isset($_POST["{$obj->attributes()->id}"]))
$this->rules["{$obj->attributes()->id}"]['value']=stripslashes($_POST["{$obj->attributes()->id}"]);
else
$this->rules["{$obj->attributes()->id}"]['value']=(string)$obj->input->attributes()->value;
foreach ($obj as $att => $val) {
switch($att) {
case 'error':
break;
case 'compulsory':
$this->findRules('compulsory',$val->attributes(),$obj->attributes()->id);
break;
case 'regexp':
$this->findRules('regexp',$val->attributes(),$obj->attributes()->id);
break;
case 'validate':
$this->findRules('validate',$val->attributes(),$obj->attributes()->id);
break;
case 'match':
$this->findRules('match',$val->attributes(),$obj->attributes()->id);
break;
case 'callback':
$this->findRules('callback',$val->attributes(),$obj->attributes()->id);
break;
case 'text':
$this->findRules('text',$val->attributes(),$obj->attributes()->id);
break;
case 'minLength':
$this->findRules('minLength',$val->attributes(),$obj->attributes()->id);
break;
case 'maxLength':
$this->findRules('maxLength',$val->attributes(),$obj->attributes()->id);
break;
}
}
$this->elements[] = (string)$obj->attributes()->id;
}
else if (($this->rules["{$obj->attributes()->id}"]['type']=='checkbox') || ($this->rules["{$obj->attributes()->id}"]['type']=='radio')) {
$this->rules["{$obj->attributes()->id}"]['value']=(string)$obj->input->attributes()->value;
if (@isset($obj->checked->attributes()->value)) {
if ($obj->checked->attributes()->value=='true') {
$this->rules["{$obj->attributes()->id}"]['checked']=true;
}
else
$this->rules["{$obj->attributes()->id}"]['checked']=false;
}
else
$this->rules["{$obj->attributes()->id}"]['checked']=false;
if (isset($_POST)) {
if ($this->rules["{$obj->attributes()->id}"]['type']=='checkbox') {
if (count($_POST)!=0) {
if (isset($_POST["{$obj->attributes()->id}"]))
$this->rules["{$obj->attributes()->id}"]['checked']=true;
else
$this->rules["{$obj->attributes()->id}"]['checked']=false;
}
}
else if ($this->rules["{$obj->attributes()->id}"]['type']=='radio') {
if (count($_POST)!=0) {
if (isset($_POST["{$obj->input->attributes()->name}"])) {
if ($_POST["{$obj->input->attributes()->name}"]==$this->rules["{$obj->attributes()->id}"]['value'])
$this->rules["{$obj->attributes()->id}"]['checked']=true;
else
$this->rules["{$obj->attributes()->id}"]['checked']=false;
}
else {
$this->rules["{$obj->attributes()->id}"]['checked']=false;
}
}
}
}
foreach ($obj as $att => $val) {
switch ($att) {
case 'error':
break;
case 'callback':
//if($this->rules["{$obj->attributes()->id}"]['type']=='checkbox')
$this->findRules('callback',$val->attributes(),$obj->attributes()->id);
break;
}
}
$this->elements[] = (string)$obj->attributes()->id;
}
else {
if (isset($_POST["{$obj->attributes()->id}"]))
$this->rules["{$obj->attributes()->id}"]['value']=stripslashes($_POST["{$obj->attributes()->id}"]);
else
$this->rules["{$obj->attributes()->id}"]['value']=(string)$obj->input->attributes()->value;
}
//Finish extract
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
case 'textarea':
if (isset($obj->attributes()->id)) {
$this->count++;
//Extract the rules
$this->rules["{$obj->attributes()->id}"] = array();
$this->rules["{$obj->attributes()->id}"]['type'] = (string)'textarea';
$this->callbacks = 0;
if(isset($_POST["{$obj->attributes()->id}"]))
$this->rules["{$obj->attributes()->id}"]['value']=stripslashes($_POST["{$obj->attributes()->id}"]);
else
$this->rules["{$obj->attributes()->id}"]['value']=str_replace('</value>','',str_replace('<value>','',(string)$obj->value->asXML()));
foreach ($obj as $att => $val) {
switch ($att) {
case 'error':
break;
case 'compulsory':
$this->findRules('compulsory',$val->attributes(),$obj->attributes()->id);
break;
case 'regexp':
$this->findRules('regexp',$val->attributes(),$obj->attributes()->id);
break;
case 'validate':
$this->findRules('validate',$val->attributes(),$obj->attributes()->id);
break;
case 'match':
$this->findRules('match',$val->attributes(),$obj->attributes()->id);
break;
case 'callback':
$this->findRules('callback',$val->attributes(),$obj->attributes()->id);
break;
case 'text':
$this->findRules('text',$val->attributes(),$obj->attributes()->id);
break;
case 'minLength':
$this->findRules('minLength',$val->attributes(),$obj->attributes()->id);
break;
case 'maxLength':
$this->findRules('maxLength',$val->attributes(),$obj->attributes()->id);
break;
}
}
$this->elements[] = (string)$obj->attributes()->id;
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
case 'select':
if (isset($obj->attributes()->id)) {
$this->count++;
//Extract the rules
$this->rules["{$obj->attributes()->id}"] = array();
$this->rules["{$obj->attributes()->id}"]['type'] = 'select';
if (isset($obj->default)) {
if (isset($obj->default->attributes()->value)) {
$default = (string)$obj->default->attributes()->value;
}
else
$default = (string)$obj->option[0]->attributes()->value;
}
else
$default = (string)$obj->option[0]->attributes()->value;
if(isset($_POST["{$obj->attributes()->id}"]))
$this->rules["{$obj->attributes()->id}"]['value']=stripslashes($_POST["{$obj->attributes()->id}"]);
else
$this->rules["{$obj->attributes()->id}"]['value']=$default;
$flago = false;
$countop = 0;
foreach($obj as $tmp=>$tmp2) {
if ($tmp=='option')
$countop++;
}
for ($i=0;$i<$countop;$i++) {
if (isset($obj->option[$i]->attributes()->value)) {
if ($obj->option[$i]->attributes()->value==$this->rules["{$obj->attributes()->id}"]['value']) {
$flago = true;
continue;
}
}
}
if ($flago==false)
throw new Exception("An invalid value was passed to the select element. Please refresh the page and try again.");
$this->callbacks = 0;
$options = '';
foreach ($obj as $att => $val) {
switch($att) {
case 'error':
break;
case 'default':
break;
case 'callback':
$this->findRules('callback',$val->attributes(),$obj->attributes()->id);
break;
}
}
$this->elements[] = (string)$obj->attributes()->id;
//Finish extract
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
}
}
}
$this->displayChildrenRecursive($obj,$depth+1);
}
}
public function FormProcessor($xml,$conf=array()) {
$this->config['display'] = true;
$this->config['csrf'] = true;
foreach($conf as $con=>$conv) {
if (isset($this->config[$con])) {
$this->config[$con] = $conv;
}
}
libxml_use_internal_errors(true);
$this->formml = $xml;
$this->formxml = simplexml_load_string($xml);
$doc = explode("\n", $xml);
if (!$this->formxml) {
$errors = libxml_get_errors();
foreach ($errors as $error) {
$xmlErrors = $this->printXMLerrors($error, $doc);
libxml_clear_errors();
throw new Exception($xmlErrors);
}
}
if (isset($this->formxml->attributes()->id)) {
if (strlen($this->formxml->attributes()->id)==0) {
throw new Exception("The form id attribute needs a value");
}
}
else
throw new Exception("The form needs an id attribute");
if (isset($_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][0])) {
$this->randomkey1 = $_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][0];
$this->randomkey2 = $_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][1];
}
else {
$_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"] = array();
$this->randomkey1 = $_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][0] = rand(1,20);
$this->randomkey2 = $_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][1] = microtime()*rand(1,20);
}
$this->displayChildrenRecursive($this->formxml);
}
private function printXMLerrors($error,$xml) {
$errorstr = '';
switch ($error->level) {
case LIBXML_ERR_WARNING:
$errorstr .= "<span style=\"font-weight:bold\">Warning (No $error->code)</span>";
break;
case LIBXML_ERR_ERROR:
$errorstr .= "<span style=\"font-weight:bold\">Error (No $error->code)</span>";
break;
case LIBXML_ERR_FATAL:
$errorstr .= "<span style=\"font-weight:bold\">Fatal error (No $error->code)</span>";
break;
}
$errorstr .= '<br />';
$msg = trim($error->message);
if (substr($msg,0,28)=='Premature end of data in tag') {
$msg = substr($msg,28);
$tmp = explode(' ',$msg);
$errorstr .= 'The <'.$tmp[1].'> tag was not closed.';
$lineno = $tmp[1];
}
else if(substr($msg,0,32)=='Opening and ending tag mismatch:') {
$msg = substr($msg,33);
$tmp = explode(' ',$msg);
$errorstr .= 'The <'.$tmp[0].'> tag was not closed.';
$errorstr .= "<br />Line ";
$errorstr .= $tmp[2]-1;
$lineno = $tmp[2]-1;
}
else {
$errorstr .= trim($error->message) ."\n";
$errorstr .= "<br />Line ";
$errorstr .= $error->line-1;
$lineno = $error->line-1;
}
$errorstr .= "<hr />";
if ($error->file) {
$errorstr .= "\n File: $error->file";
}
$errorstr .= '<table>';
for ($i=0;$i<count($xml);$i++) {
if (($i>($lineno-4)) && ($i<($lineno+4))) {
if ($lineno==($i))
$errorstr .= '<tr class="lastrow"><td style="width:80px">Line '.($i).':</td><td class="lastcol" style="background-color:yellow">'.htmlentities($xml[$i]).'</td></tr>';
else
$errorstr .= '<tr><td>Line '.($i).':</td><td class="lastcol" style="filter:alpha(opacity=50);-moz-opacity:0.5;-khtml-opacity: 0.5;opacity: 0.5;">'.htmlentities($xml[$i]).'</td></tr>';
}
else
$errorstr .= '<tr><td>Line '.($i).':</td><td class="lastcol" style="filter:alpha(opacity=20);-moz-opacity:0.2;-khtml-opacity: 0.2;opacity: 0.2;">'.htmlentities($xml[$i]).'</td></tr>';
}
return "</table>$errorstr\n\n";
}
private function findRules($type,$rule,$id) {
switch ($type) {
case 'compulsory':
$this->rules["$id"]['compulsory'] = array();
if (isset($rule->message)) {
$this->rules["$id"]['compulsory']['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['compulsory']['error'] = 'Field \''.$id.'\' needs to be filled in';
}
break;
case 'regexp':
$this->rules["$id"]['regexp'] = array();
if (isset($rule->test)) {
$this->rules["$id"]['regexp']['test'] = (string)$rule->test;
}
else
throw new Exception("A test must be specified for the regexp rule on field '$id'. E.g. <regexp test=\"|^[a-zA-Z]*$|\" message=\"$id is invalid\" />");
if (isset($rule->message)) {
$this->rules["$id"]['regexp']['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['regexp']['error'] = 'Field \''.$id.'\' is invalid';
}
break;
case 'validate':
$this->rules["$id"]['validate'] = array();
if (isset($rule->test)) {
if (($rule->test=='alpha') || ($rule->test=='alphanumeric') || ($rule->test=='numeric') || ($rule->test=='email')) {
$this->rules["$id"]['validate']['test'] = (string)$rule->test;
}
else
throw new Exception("The validate rule on field '$id' has an invalid test. It must be alpha, alphanumeric, numeric or email.");
}
else
throw new Exception("A test must be specified for the validate rule on field '$id'. E.g. <regexp test=\"|^[a-zA-Z]*$|\" message=\"$id is invalid\" />");
if (isset($rule->message))
$this->rules["$id"]['validate']['error'] = (string)$rule->message;
else {
$this->rules["$id"]['validate']['error'] = 'Field \''.$id.'\' is invalid';
}
break;
case 'match':
$this->rules["$id"]['match'] = array();
if (isset($rule->element)) {
if (in_array($rule->element,$this->elements))
$this->rules["$id"]['match']['element'] = (string)$rule->element;
else
throw new Exception("The match rule on field '$id' specifies an element which can't be found.");
}
else
throw new Exception("An element must be specified for the match rule on field '$id'. E.g. <match element=\"anotherElement\" message=\"$id must match anotherElement\" />");
if (isset($rule->message)) {
$this->rules["$id"]['match']['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['match']['error'] = 'Field \''.$id.'\' must match';
}
break;
case 'callback':
if (!isset($this->rules["$id"]['callback']))
$this->rules["$id"]['callback'] = array();
$this->rules["$id"]['callback'][$this->callbacks] = array();
if (isset($rule->function)) {
if($rule->function)
$this->rules["$id"]['callback'][$this->callbacks]['function'] = (string)$rule->function;
else
throw new Exception("The callback rule on field '$id' specifies a function which can't be found.");
}
else
throw new Exception("An function must be specified for the callback rule on field '$id'. E.g. <callback function=\"myFunction\" message=\"$id isn't valid\" />");
if (isset($rule->message)) {
$this->rules["$id"]['callback'][$this->callbacks]['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['callback'][$this->callbacks]['error'] = 'Field \''.$id.'\' is invalid';
}
$this->callbacks++;
break;
case 'text':
$this->rules["$id"]['text'] = array();
if (isset($rule->transform)) {
if (($rule->transform=='upper') || ($rule->transform=='lower') || ($rule->transform=='ucwords')) {
$this->rules["$id"]['text']['transform'] = (string)$rule->transform;
}
else
throw new Exception("The text transform has an invalid value. It must be lower, upper or ucwords.");
}
else
throw new Exception("The text rule doesn't have a transform value. E.g. <text transform=\"upper\" />");
break;
case 'minLength':
$this->rules["$id"]['minLength'] = array();
if (isset($rule->length)) {
if (is_numeric((int)$rule->length))
$this->rules["$id"]['minLength']['length'] = (int)$rule->length;
else
throw new Exception("The length attribute for field '$id' isn't a number.");
}
else
throw new Exception("The minLength field '$id' doesn't specify a length. E.g. <minLength length=\"3\" message=\"Too short!\" />");
if (isset($rule->message)) {
$this->rules["$id"]['minLength']['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['minLength']['error'] = 'Field \''.$id.'\' is too short';
}
break;
case 'maxLength':
$this->rules["$id"]['maxLength'] = array();
if (isset($rule->length)) {
if (is_numeric((int)$rule->length))
$this->rules["$id"]['maxLength']['length'] = (int)$rule->length;
else
throw new Exception("The length attribute for field '$id' isn't a number.");
}
else
throw new Exception("The maxLength field '$id' doesn't specify a length. E.g. <maxLength length=\"5\" message=\"Too long!\" />");
if (isset($rule->message)) {
$this->rules["$id"]['maxLength']['error'] = (string)$rule->message;
}
else {
$this->rules["$id"]['maxLength']['error'] = 'Field \''.$id.'\' is too short';
}
break;
}
}
private function replaceFormML($search_bef,$replace,$search_end) {
$key = strpos($this->formml,$search_bef);
$key2 = strpos($this->formml,$search_end)+strlen($search_end);
$this->formml = str_replace(substr($this->formml,$key,$key2-$key),$replace,$this->formml);
}
private function displayChildrenRecursive2($xmlObj,$depth=0) {
foreach ($xmlObj->children() as $obj) {
if ($obj->getName()=='element') {
$props = array();
foreach ($obj as $prop => $prop2) {
$props[] = $prop;
}
$formels = array('input', 'select', 'textarea');
$type = '';
foreach ($formels as $formel) {
if (in_array($formel, $props)) {
$type = $formel;
break;
}
}
if (strlen($type)!=0) {
switch ($type) {
case 'input':
if (isset($obj->attributes()->id)) {
$this->count++;
$ignore = array('name','id','value');
//Build the input tag
$str = '<input id="'.$obj->attributes()->id.'"';
if (isset($obj->input->attributes()->name))
$str .= ' name="'.$obj->input->attributes()->name.'"';
else
$str .= ' name="'.$obj->attributes()->id.'"';
if ($this->rules["{$obj->attributes()->id}"]['type']!='password') {
$str .= ' value="'.htmlentities(stripslashes($this->rules["{$obj->attributes()->id}"]["value"])).'"';
}
if (($this->rules["{$obj->attributes()->id}"]['type']=='checkbox') || ($this->rules["{$obj->attributes()->id}"]['type']=='radio')) {
if ($this->rules["{$obj->attributes()->id}"]['checked']==true)
$str .= ' checked="checked"';
$ignore[] = 'checked';
}
foreach ($obj->input->attributes() as $att => $val) {
if (!in_array($att,$ignore)) {
$str .= ' '.$att.'="'.$val.'"';
}
}
$str .= ' />'.$this->displayErrorMarker($obj);
$this->replaceFormML('<element id="'.$obj->attributes()->id.'"',$str,'</element>');
//End build
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
case 'select':
if (isset($obj->attributes()->id)) {
$this->count++;
//Extract the rules
$this->callbacks = 0;
$options = '';
foreach ($obj as $att => $val) {
switch($att) {
case 'error':
break;
case 'option':
if (isset($val->attributes()->value)) {
if ($this->rules["{$obj->attributes()->id}"]["value"]==(string)$val->attributes()->value)
$options .= '<option selected="selected" value="'.htmlentities(stripslashes($val->attributes()->value)).'">';
else
$options .= '<option value="'.htmlentities(stripslashes($val->attributes()->value)).'">';
}
else
$options .= '<option value="">';
if (isset($val->attributes()->text))
$options .= $val->attributes()->text."</option>\n";
else
$options .= "</option>\n";
break;
}
$this->elements[] = (string)$obj->attributes()->id;
}
//Finish extract
//Build the select tag
$str = '<select id="'.$obj->attributes()->id.'" name="'.$obj->attributes()->id.'"';
foreach ($obj->select->attributes() as $att => $val) {
$str .= ' '.$att.'="'.$val.'"';
}
$str .= ">\n".$options."</select>".$this->displayErrorMarker($obj);
$this->replaceFormML('<element id="'.$obj->attributes()->id.'"',$str,'</element>');
//End build
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
case 'textarea':
if (isset($obj->attributes()->id)) {
$this->count++;
$ignore = array('name','id');
//Build the input tag
$str = '<textarea id="'.$obj->attributes()->id.'" name="'.$obj->attributes()->id.'"';
foreach ($obj->textarea->attributes() as $att => $val) {
if (!in_array($att,$ignore)) {
$str .= ' '.$att.'="'.$val.'"';
}
}
$str .= '>'.stripslashes($this->rules["{$obj->attributes()->id}"]["value"]).'</textarea>'.$this->displayErrorMarker($obj);
$this->replaceFormML('<element id="'.$obj->attributes()->id.'"',$str,'</element>');
//End build
}
else {
throw new Exception('The ID was not found for form element no'.$this->count.'! It should be in the format <element id="myid">');
}
break;
}
}
}
$this->displayChildrenRecursive2($obj,$depth+1);
}
}
private function displayErrorMarker($obj) {
$key = strpos($this->formml,'<element id="'.$obj->attributes()->id);
$key2 = strpos($this->formml,'</element>',$key)+10;
$tmp = substr($this->formml,$key,$key2-$key);
$key = strpos($tmp,'<error>')+7;
if ($key!=NULL) {
$key2 = strpos($tmp,'</error>');
$erroro = substr($tmp,$key,$key2-$key);
if (isset($this->errors["{$obj->attributes()->id}"]))
return $erroro;
}
}
public function display() {
//Rebuild the form tag
$str = '<form id="'.$this->formxml->attributes()->id.'" name="'.$this->formxml->attributes()->id.'"';
foreach ($this->formxml->attributes() as $att => $val) {
if (($att!='id') && ($att!='name')) {
$str .= ' '.$att.'="'.$val.'"';
}
}
$str .= ">\n\r<div><input type=\"hidden\" name=\"token\" id=\"token\" value=\"".md5($this->randomkey1.'-'.$this->randomkey2)."\" /></div>";
$this->replaceFormML('<form',$str,'>');
//End rebuild
$this->displayChildrenRecursive2($this->formxml);
if (isset($this->formxml->errorlist)) {
//Generate the errorlist
$errorlist = $this->formxml->errorlist->asXML();
$errorlist = substr($errorlist,11);
$errorlist = trim(substr($errorlist,0,strlen($errorlist)-13));
$key = strpos($errorlist,'<erroritem>');
if ($key==NULL)
throw new Exception('The erroritem tag doesn\'t exist, or needs a container tag around it. The erroritem tag is required to print error messages when form data isn\'t valid.');
$key = $key + 11;
$erroritem = substr($errorlist,$key);
$key = strpos($erroritem,'</erroritem>');
$erroritem = trim(substr($erroritem,0,$key));
$errors = '';
if (strpos($erroritem,'<error/>')==NULL)
throw new Exception('The error tag doesn\'t exist, or needs a container tag around it. It is required to print error messages when form data isn\'t valid.');
foreach ($this->errors as $erroro) {
$errors .= str_replace('<error/>',$erroro,$erroritem);
}
$key = strpos($errorlist,'<erroritem>');
$errors = substr($errorlist,0,$key).$errors;
$key = strpos($errorlist,'</erroritem>');
$errorlist = substr($errorlist,$key+12);
$errors = $errors.$errorlist;
if (count($this->errors)==0)
$this->replaceFormML('<errorlist>','','</errorlist>');
else
$this->replaceFormML('<errorlist>',$errors,'</errorlist>');
//End the generate
}
else
throw new Exception('The errorlist tag doesn\'t exist. It is required to print error messages when form data isn\'t valid.');
if($this->config['display']==true)
echo $this->formml;
else
return $this->formml;
}
public function validate($token=true) {
if (!$_POST) {
return false;
}
if ($this->config['csrf']==true) {
if (!isset($_POST["token"])) {
$this->errors["token"] = 'The form was invalid. Please refresh the page and try again.';
return false;
}
if ($_POST["token"]!=md5($this->randomkey1.'-'.$this->randomkey2)) {
$this->errors["token"] = 'The form was invalid. Please refresh the page and try again.';
return false;
}
}
foreach ($this->rules as $name => $rule) {
if (isset($this->rules[$name]['compulsory'])) {
if ((!isset($_POST[$name])) || (trim($_POST[$name]) == '')) {
$this->errors[$name] = $this->rules[$name]['compulsory']['error'];
continue;
}
}
if (isset($this->rules[$name]['regexp'])) {
if(!preg_match($this->rules[$name]['regexp']['test'], stripslashes($_POST[$name]))) {
$this->errors[$name] = $this->rules[$name]['regexp']['error'];
continue;
}
}
if (isset($this->rules[$name]['validate'])) {
switch($this->rules[$name]['validate']['test']) {
case 'alpha';
$regexp = "|^[a-zA-Z]*$|";
break;
case 'alphanumeric';
$regexp = "|^[a-zA-Z0-9]*$|";
break;
case 'numeric';
$regexp = "|^[0-9]*$|";
break;
case 'email';
$regexp = "/^[-_a-z0-9\'+*$^&%=~!?{}]++(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*+@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d++)?$/iD";
break;
}
if (!preg_match($regexp, stripslashes($_POST[$name]))) {
$this->errors[$name] = $this->rules[$name]['validate']['error'];
continue;
}
}
if (isset($this->rules[$name]['text'])) {
switch($this->rules[$name]['text']['transform']) {
case 'lower':
$_POST[$name] = strtolower(stripslashes($_POST[$name]));
break;
case 'upper':
$_POST[$name] = strtoupper(stripslashes($_POST[$name]));
break;
case 'ucwords':
$_POST[$name] = ucwords(stripslashes($_POST[$name]));
break;
}
}
if (isset($this->rules[$name]['minLength'])) {
if(strlen($_POST[$name])<$this->rules[$name]['minLength']['length']) {
$this->errors[$name] = $this->rules[$name]['minLength']['error'];
continue;
}
}
if (isset($this->rules[$name]['maxLength'])) {
if(strlen($_POST[$name])>$this->rules[$name]['maxLength']['length']) {
$this->errors[$name] = $this->rules[$name]['maxLength']['error'];
continue;
}
}
if (isset($this->rules[$name]['match'])) {
if ($_POST[$this->rules[$name]['match']['element']]!=$_POST[$name]) {
$this->errors[$name] = $this->rules[$name]['match']['error'];
continue;
}
}
if (isset($this->rules[$name]['callback'][0])) {
for ($i=0;$i<count($this->rules[$name]['callback']);$i++) {
if (function_exists($this->rules[$name]['callback'][$i]['function'])) {
if ($this->rules[$name]['type']=='checkbox') {
if (isset($_POST[$name]))
$tmp = true;
else
$tmp = false;
if (!$this->rules[$name]['callback'][$i]['function']($tmp)) {
$this->errors[$name] = $this->rules[$name]['callback'][$i]['error'];
continue 2;
}
}
else {
if(!$this->rules[$name]['callback'][$i]['function']($_POST[$name])) {
$this->errors[$name] = $this->rules[$name]['callback'][$i]['error'];
continue 2;
}
}
}
else
throw new Exception('Function '.$this->rules[$name]['callback'][$i]['function'].' couldn\'t be found! It was specified in the callback for the field \''.$name.'\'.');
}
}
}
if(count($this->errors)!=0) {
return false;
}
unset($_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][0]);
unset($_SESSION["formprocessor"][$_SERVER["PHP_SELF"]]["{$this->formxml->attributes()->id}"][1]);
return true;
}
}
?>