Location: PHPKode > scripts > PHP Form Processor > php-form-processor/class.formprocessor.php
<?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 &lt;element id="myid"&gt;');
							}

						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 &lt;element id="myid"&gt;');
							}
						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 &lt;element id="myid"&gt;');
							}
						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 &lt;'.$tmp[1].'&gt; 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 &lt;'.$tmp[0].'&gt; 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. &lt;regexp test=\"|^[a-zA-Z]*$|\" message=\"$id is invalid\" /&gt;");
					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. &lt;regexp test=\"|^[a-zA-Z]*$|\" message=\"$id is invalid\" /&gt;");

				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. &lt;match element=\"anotherElement\" message=\"$id must match anotherElement\" /&gt;");

				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. &lt;callback function=\"myFunction\" message=\"$id isn't valid\" /&gt;");

				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. &lt;text transform=\"upper\" /&gt;");
			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. &lt;minLength length=\"3\" message=\"Too short!\" /&gt;");

				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. &lt;maxLength length=\"5\" message=\"Too long!\" /&gt;");

				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 &lt;element id="myid"&gt;');
							}

						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 &lt;element id="myid"&gt;');
							}

							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 &lt;element id="myid"&gt;');
								}
							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; 
	} 
} 
?>
Return current item: PHP Form Processor