Location: PHPKode > projects > chillyCMS > chillyCMS/core/form.class.php
<?php
//#################################################################################################
//	Class Form
//#################################################################################################
//	chillyCMS - Content Management System
//	Copyright (C) 2008
//	Stefanie Wiegand <hide@address.com> & Johannes Cox <hide@address.com>
//	
//	This program is licensed under the GPL 3.0 license. For more information see LICENSE.txt.
//#################################################################################################
defined('DOIT') or die('Restricted access');

require_once('formelement.class.php');

class Form {
	//Class variables//////////////////////////////////////////////////////////////////////////
	private $action;
	private $method;
	private $name;
	private $token;
	private $elements = array();
	private $errors = array();
	public $sent;
	private $compulsorynotice;
	private $showaftersuccess;
	private $enctype;
	public $msggood;
	public $msgbad;
	//Functions////////////////////////////////////////////////////////////////////////////////
	public function __construct($action='',$method='post',$name='',$msggood='',$msgbad='',$compulsorynotice='',$showaftersuccess=true) {
		$this->action = $action;
		$this->method = strtolower($method);
		$this->name = $name;
		$this->compulsorynotice = $compulsorynotice;
		$this->showaftersuccess = $showaftersuccess;
		$this->msggood = $msggood;
		$this->msgbad = $msgbad;
		$this->enctype = 'application/x-www-form-urlencoded';	//default enctype, only changed later if the form contains >1 file inputs
		//generate token
		$this->token = mt_rand().md5($_SERVER["HTTP_USER_AGENT"]).mt_rand().md5(time()).mt_rand();
		$this->elements[] = new FormInput("hidden","token",false,$this->token);
		if (!isset($_SESSION)) { session_start(); }
		if (!isset($_SESSION["tokens"])) { $_SESSION["tokens"] = array(); }
		$_SESSION["tokens"][] = $this->token;
		//send formname for comparison if it was already sent
		$this->elements[] = new FormInput("hidden","thisformname",false,$this->name);
		//find out if the form was already sent
		if ($this->method == 'get') {
			$this->sent = (isset($_GET['thisformname']) && $_GET['thisformname']==$this->name);
		} elseif($this->method == 'post') {
			$this->sent = (isset($_POST['thisformname']) && $_POST['thisformname']==$this->name);
		}
	}
	//Getter
	public function __get($name) {
		if (isset($name, $this->$name)) { return $this->$name; }
		else { return false; }
	}
	//Add an Input-element
	public function addInput($type,$name,$text=false,$value=false,$compulsory=false,$check=false,$size=false,$maxlength=false,$cols=false,$rows=false,$id=false,$class=false,$title=false,$errorhint=false,$javascript=false) {
		$success = false;
		$fi = false;
		switch ($type) {
			case 'text':
				$fi = new FormInput('text',$name,$text,$value,$compulsory,$check,$size,$maxlength,false,false,$id,$class,$title,$errorhint,$javascript);
				break;
			case 'password':
				$fi = new FormInput('password',$name,$text,$value,$compulsory,$check,$size,$maxlength,false,false,$id,$class,$title,$errorhint,$javascript);
				break;
			case 'textarea':
				$fi = new FormInput('textarea',$name,$text,$value,$compulsory,$check,$size,$maxlength,$cols,$rows,$id,$class,$title,$errorhint,$javascript);
				break;
			case 'hidden':
				$fi = new FormInput('hidden',$name,$text,$value,false,$check,false,false,false,false,$id,$class,false,false,false);
				break;
			case 'submit':
				$fi = new FormInput('submit',$name,$text,$value,false,false,false,false,false,false,$id,$class,$title,$errorhint,$javascript);
				break;
			case 'reset':
				$fi = new FormInput('reset',$name,$text,$value,false,false,false,false,false,false,$id,$class,$title,false,$javascript);
				break;
			default:
				break;
		}
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}
	
	//Add a checkbox with one or more options or a group of radiobuttons
	public function addChoice($type,$name,$text,$options,$compulsory=false,$selected=false,$id=false,$class=false,$title=false,$errorhint=false,$javascript=false) {
		$success = false;
		$fi = new FormChoice($type,$name,$text,$options,$compulsory,$selected,$id,$class,$title,$errorhint,$javascript);	
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}
	
	//Add a select field or dropdownbox
	public function addSelect($name,$text,$options,$compulsory=false,$selected=false,$size=1,$multiple=false,$id=false,$class=false,$title=false,$errorhint=false,$javascript=false) {
		$success = false;
		$fi = new FormSelect($name,$text,$options,$compulsory,$selected,$size,$multiple,$id,$class,$title,$errorhint,$javascript);
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}

	//Add a button
	public function addButton($type,$name,$text=false,$value=false,$link=false,$id=false,$class=false,$title=false,$javascript=false) {
		$success = false;
		$fi = new FormButton($type,$name,$text,$value,$link,$id,$class,$title,$javascript);
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}
	
	//Add an upload field
	public function addFile($name,$text=false,$compulsory=false,$check=false,$size=false,$accept=false,$id=false,$class=false,$title=false,$errorhint=false,$javascript=false) {
		$success = false;
		$fi = new FormFile($name,$text,$compulsory,$check,$size,$accept,$id,$class,$title,$errorhint,$javascript);
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	
	}

	//Add a textrow
	public function addTextrow($name,$text=false,$longtext=false,$size=1,$id=false,$class=false,$title=false,$javascript=false) {
		$success = false;
		$fi = new FormTextrow($name,$text,$longtext,$size,$id,$class,$title,$javascript);
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}
	
	//Add a captchafield (=singleton!!!)
	public function addCaptcha($name,$text=false,$id=false,$class=false,$title=false,$errorhint=false) {
		$success = false;
		$fi = new FormCaptcha($name,$text,$id,$class,$title,$errorhint);
		if ($fi->valid) {
			$this->elements[] = $fi;
			$success = true;
		}
		return $success;
	}
	
	//get REQUEST values into form elements
	public function getValues() {
		//check method
		if ($this->method == "post" or $this->method == "get") {
			//escape values
			$post = escape_html($_POST);
			$get = escape_html($_GET);
			if (is_array($this->elements) && !empty($this->elements)) {
				//run through elements
				foreach ($this->elements as $e) {
					//remove spaces from input name if any, because php does so as well
					$safename = str_replace(' ','_',$e->name);
					//if there were actually spaces in the name
					if (!isset(${$this->method}[$e->name]) && isset(${$this->method}[$safename])) {
						//take the values from the php generated safe name and save them under the real name
						${$this->method}[$e->name] = ${$this->method}[$safename];	
					}
					//if there is a value set for that element
					if (isset(${$this->method}[$e->name])) {
						$class = get_class($e);
						//only look at classes that are allowed
						switch ($class) {
							case 'FormInput':
								$allowed = array('text','textarea');
								if (in_array($e->type,$allowed)) {
									$e->value = ${$this->method}[$e->name];
								}
								break;
							case 'FormSelect':
								if (is_array(${$this->method}[$e->name]) && !empty(${$this->method}[$e->name])) {
									$e->select(${$this->method}[$e->name]);
								} elseif (sizeof(${$this->method}[$e->name])>0) {
									$e->select(array(${$this->method}[$e->name]));
								}							
								break;
							case 'FormChoice':
								if (is_array(${$this->method}[$e->name]) && !empty(${$this->method}[$e->name])) {
									$e->select(${$this->method}[$e->name]);
								} elseif (sizeof(${$this->method}[$e->name])>0) {
									$e->select(array(${$this->method}[$e->name]));
								}
								break;
							default:
								break;
						}
					}
				}
			}
		}
	}
	
	//check token
	public function checkToken() {
		$result = false;
		if (!$_SESSION or !is_array($_SESSION)) { session_start(); }
		if ($this->method == "post") {
			if (isset($_POST["token"]) && is_array($_SESSION["tokens"]) && in_array($_POST["token"],$_SESSION["tokens"])) {
				remove_by_val($_SESSION["tokens"],$_POST["token"]);
				$result = true;
			}
		} elseif ($this->method == "get") {
			if (isset($_GET["token"]) && is_array($_SESSION["tokens"]) && in_array($_GET["token"],$_SESSION["tokens"])) {
				remove_by_val($_SESSION["tokens"],$_GET["token"]);
				$result = true;
			}
		}
		return $result;
	}
	
	//check form
	public function getErrors($checktoken=true) {
		//find out if the form was already sent
		if ($this->method == 'get') {
			$this->sent = isset($_GET['token']);
		} elseif($this->method == 'post') {
			$this->sent = isset($_POST['token']);
		}
		if ($this->sent) {
			$errors = array();
			//check token
			if ($checktoken) {
				if (!$this->checkToken()) { $errors[] = 'token'; }
			}
			//check compulsory fields
			if (is_array($this->elements) && !empty($this->elements) && ($this->method=='get' or $this->method=='post')) {
				foreach($this->elements as $e) {
					//check captcha
					if (get_class($e)=='FormCaptcha') {
						if (isset($_POST["recaptcha_challenge_field"]) && isset($_POST["recaptcha_response_field"])) {
							$e->resp = recaptcha_check_answer($e->privatekey,$_SERVER["REMOTE_ADDR"],$_POST["recaptcha_challenge_field"],$_POST["recaptcha_response_field"]);
							if (!$e->resp->is_valid) {
								//set error
								$errors[] = $e->name;
								$e->captchaerror = $e->resp->error;
								//tell the element it is wrong
								$e->error = true;
							}
						} else {
							//set error
							$errors[] = $e->name;
							$e->captchaerror = 'reCaptcha challenge- or response field not set';
							//tell the element it is wrong
							$e->error = true;
						}
						continue;
					}
					if ($e->compulsory) {
						$post = escape_html($_POST);
						$get = escape_html($_GET);
						//value is not set or empty
						if (!isset(${$this->method}[$e->name]) or !${$this->method}[$e->name] or ${$this->method}[$e->name]=='') {
							//value is not already in error array
							if (!in_array($e->name,$errors)) {
								//set error
								$errors[] = $e->name;
								//tell the element it is wrong
								$e->error = true;
							}
						}
					}
					//custom check value using regular expressions
					if (isset(${$this->method}[$e->name]) && $e->check && $e->check[0] && strlen($e->check[0])>0) {
						if (!preg_match($e->check[0],${$this->method}[$e->name])) {
							//value is not already in error array
							if (!in_array($e->name,$errors)) {
								//set error
								$errors[] = $e->name;
								//tell the element it is wrong
								$e->error = true;
							}
						}
					}
				}
			}
			$this->errors = $errors;
		}		
	}

	//set a field false
	public function setError($fieldname) {
		$done = false;
		//check if the field exists
		foreach ($this->elements as $e) {
			if (is_array($fieldname)&& !empty($fieldname)) {
				foreach ($fieldname as $f) {
					if ($e->name==$f && !in_array($e->name,$this->errors)) {
						$this->errors[] = $e->name;
						$e->error = true;
						$done = true;
					}
				}
			} else {
				if ($e->name==$fieldname && !in_array($e->name,$this->errors)) {
					$this->errors[] = $e->name;
					$e->error = true;
					$done = true;
					break;
				}
			}
		}
		return $done;
	}
	
	//clear an error
	public function clearError($fieldname) {
		$done = false;
		//check if the field exists
		foreach ($this->elements as $e) {
			if (is_array($fieldname)&& !empty($fieldname)) {
				foreach ($fieldname as $f) {
					if ($e->name==$f && in_array($e->name,$this->errors)) {
						remove_by_val($this->errors,$e->name);
						$e->error = false;
						$done = true;
					}
				}
			} else {
				if ($e->name==$fieldname && in_array($e->name,$this->errors)) {
					remove_by_val($this->errors,$e->name);
					$e->error = false;
					$done = true;
					break;
				}
			}
		}
		return $done;
	}
	
	//get message
	public function getMsg() {
		$msg = false;
		if ($this->sent) {
			//echo sent message
			if (is_array($this->errors) && !empty($this->errors)) {
				$msg = array($this->msgbad,'bad');
			} else {
				$msg = array($this->msggood,'good');
			}
		}
		return $msg;
	}
	
	//Print Form
	public function render($style="plain",$buttons="bottom") {
		$output = '';
		if ($this->sent) {
			$this->getValues();
		}
		//compulsory asterisk
		$asterisk = '<span class="form_asterisk">*</span>';
		$mybuttons = '';

		if (!$this->sent or ($this->sent && ((empty($this->errors) && $this->showaftersuccess) or (is_array($this->errors) && !empty($this->errors))))) {
		
			//make enctype:
			//--look at each element
			foreach ($this->elements as $e) {
				//--if there is a file input
				if (get_class($e)=='FormFile') {
					//--change the enctype
					$this->enctype = 'multipart/form-data';
					//--and make sure the method is post or else it won't work.
					$this->method = 'post';
					break;
				}
				//check whether there is an error
				if ($e->error) {
					//if there is already a class append error class
					if($e->class && sizeof($e->class)>0) {
						$e->class .= ' formerror';
					//else make class error class
					} else {
						$e->class = 'formerror';
					}
				}
			}
			//begin form
			$output .= "\n<form action=\"".$this->action."\" method=\"".$this->method."\" enctype=\"".$this->enctype."\">\n";
	
			if ($style=="table") {
				$output .= "\t<h1>".$this->name."</h1>\n".
				"\t<table>\n";
				if (is_array($this->elements) && !empty($this->elements)) {
					foreach($this->elements as $e) {
						if ($e->type=="hidden") {
							$output .= "\t\t".$e->render()."\n";
						//handle buttons separately
						} elseif(get_class($e)=='FormButton' && $buttons=='bottom') {
							$mybuttons .= "\t".$e->render('with_id')."\n";
						//handle textrows
						} elseif(get_class($e)=='FormTextrow') {
							if ($e->size==1) {
								$output .= "\t\t".'<tr';
								if ($e->id) { $output .= ' id="'.$e->id.'"'; }
								$output .='><td>';
								if ($e->text && $e->text!='') {
									$output .= $e->text;
								}
								$output .= '</td><td>'.$e->render()."</td></tr>\n";
							} else {
								$output .= "\t\t".'<tr';
								if ($e->id) { $output .= ' id="'.$e->id.'"'; }
								$output .='><td colspan="2">'.$e->render()."</td></tr>\n";
							}
						} else {
							$output .= "\t\t<tr";
							if ($e->id) { $output .= ' id="'.$e->id.'"'; }
							$output .=">\n".
							"\t\t\t<td>".$e->text;
							//asterisk
							if ($e->compulsory==true && $this->compulsorynotice) { $output .= $asterisk; }
							//info hover
							if ($e->check[1] && strlen($e->check[1])>0) {
								$output .= '<span class="info floatright" title="'.$e->check[1].'">info</span>';
							}
							$output .= "</td>\n".
							"\t\t\t<td>".$e->render()."</td>\n".
							"\t\t</tr>\n";
						}
					}
				}
				$output .= "\t</table>\n";
				if ($this->compulsorynotice) {
					$output .= "\t\t<p class=\"form_noticecompulsory\">* ".$this->compulsorynotice."</p>\n";
				}
				$output .= $mybuttons;
			} elseif ($style=="fieldset") {
				$output .= "\t<fieldset>\n".
				"\t\t<legend>".$this->name."</legend>\n";
				if (is_array($this->elements) && !empty($this->elements)) {
					foreach($this->elements as $e) {
						if ($e->type=="hidden" or get_class($e)=='FormButton') {
							$output .= $e->render()."\n";
						} else {
							$output .= "\t\t<p";
							if ($e->id) { $output .= ' id="'.$e->id.'" '; }
							$output .=">\n";
							if (get_class($e)!='FormCaptcha') {
								$output .= "\t\t\t<label for=\"";
								if ($this->id && $this->id!="") {
									$output .= $e->id;
								} else {
									$output .= $e->name;
								}
								$output .= "\">".$e->text;
							}
							//asterisk
							if ($e->compulsory==true && $this->compulsorynotice) { $output .= $asterisk; }
							//info hover
							if ($e->check[1] && strlen($e->check[1])>0) {
								$output .= '<span class="info" title="'.$e->check[1].'">info</span>';
							}
							$output .= "</label>\n".
							$e->render()."\n".
							"\t\t</p>\n";
						}
					}
				}
				if ($this->compulsorynotice) {
					$output .= "\t\t<p class=\"form_noticecompulsory\">* ".$this->compulsorynotice."</p>\n";
				}
				$output .= "\t</fieldset>\n";
			} else {
				if (is_array($this->elements) && !empty($this->elements)) {
					foreach($this->elements as $e) {
						$output .= $e->render('with_id');
					}
				}
			}
			//end form
			$output .= "</form>\n";
		}
		return $output;
	}
	
	public function getCleanValues($type='html') {
		$cleanvalues = false;
		
		//if the form was sent and does not contain any errors
		if ($this->sent) {
			//check method
			if ($this->method == "post" or $this->method == "get") {
				$fileinputs = array();
				
				if ($this->method == "post") {
					$realmethod = $_POST;
					//check for file array
					if (is_array($_FILES) && !empty($_FILES)) {
						//check for inputs
						foreach ($this->elements as $e) {
							if (get_class($e)=='FormFile') {
								$fileinputs[] = $e->name;
							}
						}
					}
				} else {
					$realmethod = $_GET;
				}
				
				//escape values
				if ($type=='db' or $type=='dbnull') {
					//check is the form class is used inside chillycms, then there might already be a database connection
					global $page;

					$destroy = false;
					
					if ($page->db && !is_null($page->db)) {
						$mydb = $page->db;
					} else {
						$mydb = new Database();
						$destroy = true;
					}
					//escape!
					if ($type=='dbnull') { $nulls = true; } else { $nulls = false; }
					$cleanvalues = $mydb->escape($realmethod,$nulls);
					
					//file inputs
					if (!empty($fileinputs)) {
						foreach ($fileinputs as $fi) {
							if (isset($_FILES[$fi])) {
								$inputarray = $mydb->escape($_FILES[$fi]);
								$cleanvalues[$fi] = $inputarray;
							}
						}
					}
					
					if ($destroy===true) {
						$mydb->close();
					}
				} elseif($type=='html') {
					$cleanvalues = escape_html($realmethod);
					//file inputs
					if (!empty($fileinputs)) {
						foreach ($fileinputs as $fi) {
							if (isset($_FILES[$fi])) {
								$inputarray = escape_html($_FILES[$fi]);
								$cleanvalues[$fi] = $inputarray;
							}
						}
					}
				}
			}
		}
		return $cleanvalues;
	}
}
?>
Return current item: chillyCMS