Location: PHPKode > scripts > Skunky Form > skunky-form/Form.php
<?php
// +----------------------------------------------------------------------+
// | PHP versions 5                                                       |
// +----------------------------------------------------------------------+
// | Copyright (c) 2009 Damien Conte, Creative Area                 	  |
// | All rights reserved.                                                 |
// +----------------------------------------------------------------------+
// | This package is used to generate customs forms                       |
// | Perfect choice for your basic contact forms, feedback forms,         |
// | registration forms...                                                |
// |                                                                      |
// | This LICENSE is in the BSD license style.                            |
// |                                                                      |
// | Redistribution and use in source and binary forms, with or without   |
// | modification, are permitted provided that the following conditions   |
// | are met:                                                             |
// |                                                                      |
// | Redistributions of source code must retain the above copyright       |
// | notice, this list of conditions and the following disclaimer.        |
// |                                                                      |
// | Redistributions in binary form must reproduce the above copyright    |
// | notice, this list of conditions and the following disclaimer in the  |
// | documentation and/or other materials provided with the distribution. |
// |                                                                      |
// | Neither the name of Damien Conte, Creative Area, nor the names of his|
// | contributors may be used to endorse                                  |
// | or promote products derived from this software without specific prior|
// | written permission.                                                  |
// |                                                                      |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
// | POSSIBILITY OF SUCH DAMAGE.                                          |
// +----------------------------------------------------------------------+
// | Author: Damien Conte <hide@address.com>                            |
// +----------------------------------------------------------------------+
//

/**
 * This package is used to generate customs forms
 *
 * Perfect choice for your basic contact forms, feedback forms, registration forms...
 * 
 * Features :
 *
 * - nice template using wufoo
 * - automatic server and/or client side (no specific js framework required) validation
 * - get raw result of your post
 * - save data to your database (compatible mysql, PEAR::db, PEAR::mdb2 and PEAR::dataObject)
 * - retrieve postdata by mail
 *
 * @link http://pear.php.net/manual/en/package.database.db.php
 * @link http://pear.php.net/manual/en/package.database.mdb2.php
 * @link http://pear.php.net/manual/en/package.database.db-dataobject.php
 * @link http://wufoo.com/
 *
 * @package SkunkyForm
 * @version 0.1 (2009/12/14)
 * @author Damien CONTE (Creative Area) <hide@address.com>
 */
 
/**
 * You can choose if you want to generate the form using the method addfield or passing an array to the constructor
 *
 * The Form field's names have to match field's names of the table in the database
 *
 * You have to use this class with the js file
 *
 * The method getForm is used with the CSS folder 
 *
 * Example :
 * <code>
 *	$monForm = new Form();
 *	$monForm->addField("lastname");
 *	$monForm->addField("firstname");
 *	$monForm->addField("mail");
 *  $monForm->addField("message");
 *	$monForm->setActiveJs(true);
 *	if(!empty($_POST)) {
 *		$monForm->setFrom($_POST);
 *		if ($monForm->validate()) {
 *			$monForm->saveForm("mysql", array(
 *				"hostname" => "yourhostname", 
 *				"login" => "yourlogin", 
 *				"password" => "yourpassword", 
 *				"dbname" => "yourdatabasename"
 *			), "yourtablename");
 *			$monForm->displayResult();
 *			try {
 *				$monForm->sendByMail("hide@address.com");
 *			} catch(Exception $e){
 *				echo $e->getMessage();
 *			}
 *		} else {
 *			$monForm->displayForm();
 *		}
 *	} else {
 *		$monForm->displayForm();
 *	}
 * </code>
 *
 * @example examples/exampledataobject.php How to use with PEAR::DB_DataObject connector
 * @example examples/exampledb.php How to use with PEAR::DB connector
 * @example examples/examplemdb2.php How to use with PEAR::MDB2 connector
 * @example examples/examplemysql.php How to use with a classic MySQL connector 
 *
 * @package SkunkyForm
 */
class Form {

	/**
	 * @var     array
	 * @access  private
	 */	
	private $_arrFields = array();
	
	/**
     * @var     array
     * @access  private
     */		
	private $_arrErrors = array();
	
	/**
     * @var     array
     * @access  private
     */	
	private $_arrSucces = array();
	
	/**
     * @var     bool
     * @access  private
     */		
	private $_activeJs = false;
	
	/**
     * @var     string
     * @access  private
     */		
	private $_jsPath = "";
		
	/**
     * @var     array
     * @access  private
     */		
	private $_data = array();

    /**
     * Constructor
     *
     * @param array $arrfields  
     * @access public
     * @return void
     */	
	public function __construct($arrfields = array()) {
	
		$this->_arrFields = $arrfields;
	
	}
	
    /**
     * Method to set the javascript to on or off
     *
     * @param  bool $bool true for js on, false for js off
     * @access public
     * @return void
     */
	public function setActiveJs($bool) {
	
		$this->_activeJs = $bool;
		
	}
	
    /**
     * Method to get if the javascript is on or off
     *
     * @access private
     * @return bool
     */
	private function _getActiveJs() {
	
		return $this->_activeJs;
		
	}
	
	/**
     * Method to set the path of your js file's location
     *
     * @param  string $path 
     * @access public
     * @return void
     */
	public function setJsPath($path) {
	
		$this->_jsPath = $path;
		
	}
	
	/**
     * Method to know where is located your js file
     *
     * @access private
     * @return string
     */	
	private function _getJsPath() {
	
		return $this->_jsPath;
		
	}
	
	/**
	 * Method to get a data array
	 *
     * @access private
     * @return array
     */	
	private function _getData() {
	
		return $this->_data;
		
	}
	
	/**
     * Method to get the content of the js file
     *
     * @access private
     * @return string
     */	
	private function loadJs() {
		
		if ($this->_getActiveJs()) {
			$js_path = $this->_getJsPath();
			if (empty($js_path)) {
				$this->setJsPath(dirname(__FILE__).'/js/form.js');
			}
			$content = file_get_contents($this->_getJsPath());
			return $content;
		} else {
			$content = "";
			return $content;
		}
		
	}

	/**
     * Method to get the fields of the form
     *
     * @param string $type
     * @param string $name
     * @param bool $required
     * @param string $jsfunction
     * @param array $options
     * @param string $value
     * @access private
     * @return string
     */	
	private function _getField($type, $name, $required, $jsfunction="", $options = array(), $value="") {
	
		$class = "";
		if ($required) {
			$class .= "required ";
		}
		if (!empty($jsfunction)) {
			$class .= $jsfunction;
		}
		switch ($type) {
			case "textarea" :
			return '<textarea 
				name="'.$name.'" 
				id="'.$name.'" 
				class="field textarea medium '.$class.'" 
				onfocus="borderType(this);" onblur="validateField(this);">'
				.$value.
				'</textarea>';
			break;
			
			case "radio" :
			$retour = '';
			$i = 0;
			foreach ($options as $key => $val) {
				$checked = "";
				if ($key == $value) {
					$checked = ' checked = "checked"';
				}
				if ($i != sizeof($options) -1) {
					$radio_class = "";
				} else {
					$radio_class = $class;
				}
				$retour .= '<span><input id="'.$name.'_'.$key.'" 
					name="'.$name.'" 
					type="'.$type.'" 
					class="field radio '.$radio_class.'" 
					value="'.$key.'"'.$checked.'
					onclick="validateField(this);" 
					/>';
				$retour .= '<label class="choice">'.$val.'</label></span>';
				$i++;
			}
			return $retour;
			break;
			
			case "select" :
			$retour = '<select 
				id="'.$name.'" 
				name="'.$name.'" 
				class="field select medium '.$class.'" 
				onfocus="borderType(this);" onblur="validateField(this);"
				>';
			$retour .= '<option value="">-- select value --</option>';
			foreach ($options as $key => $val) {
				$selected = "";
				if ($key == $value) {
					$selected = ' selected = "selected"';
				}
				$retour .= '<option value="'.$key.'"'.$selected.'>'.$val.'</option>';
			}
			$retour .= '</select>';
			return $retour;
			break;

			case "checkbox" :
			$retour = "";
			foreach ($options as $key => $val) {
				$retour .= '<span><input 
					id="'.$name.'" 
					name="'.$name.'" 
					type="'.$type.'" 
					class="field checkbox '.$class.'" 
					value="1"
					onclick="validateField(this);"
					/>
					<label for="'.$name.'" class="choice">'.$val.'</label></span>';
			}
			return $retour;
			
			default:
			return '<input 
				type="text" 
				name="'.$name.'" 
				id="'.$name.'" 
				value="'.$value.'" 
				class="field text medium '.$class.'" 
				onfocus="borderType(this);" onblur="validateField(this);" 
				/>';
			break;
		}
		 
	}
	
	/**
     * Method to add a field in the form
     *
     * @param string $field_name
     * @param array $field_opt
     * @access public
     * @return void
     */		
	public function addField($field_name, $field_opt = array()) {
		
		$this->_arrFields[$field_name] = array(
			"label" => $field_name,
			"required" => false, 
			"rule" => "",
			"type" => "input",
			"errormsg" => "This field is not valid !",
			"options" => array()
		);
		if (isset($field_opt["label"])) {
			$this->_arrFields[$field_name]["label"] = $field_opt["label"];
		}
		if (isset($field_opt["required"])) {
			$this->_arrFields[$field_name]["required"] = $field_opt["required"];
		}
		if (isset($field_opt["rule"])) {
			$this->_arrFields[$field_name]["rule"] = $field_opt["rule"];
		}
		if (isset($field_opt["type"])) {
			$this->_arrFields[$field_name]["type"] = $field_opt["type"];
		}
		if (isset($field_opt["errormsg"])) {
			$this->_arrFields[$field_name]["errormsg"] = $field_opt["errormsg"];
		}
		if (isset($field_opt["options"])) {
			$this->_arrFields[$field_name]["options"] = $field_opt["options"];
		}
		
	}
	
	/**
     * Method to put the of a valid post of the form in an array
     *
     * @access public
     * @return void
     */			
	public function getRawResult() {
	
		return $this->_getData();
		
	}	
    
	/**
     * Method to get the result of a valid post of the form in a HTML page
     *
     * @access public
     * @return string
     */		    
    public function getResult() {
    	
		$str = '';
		if (!empty($this->_arrErrors)) {
			$str.= "<div><ul>";
			foreach ($this->_arrErrors as $error) {		
				$str.= "<li>" . $error . "</li>";
			}
			$str.= "</ul></div>";
		} else {
			if (!empty($this->_arrSucces)) {
				$str .= '<div class="info">
						<h2>Contact Form</h2>
						<div>Personal Informations :</div>';
				$str .= "</div><ul>";
				foreach ($this->_arrSucces as $succes) {
					$str.= '<li>' . $succes . "</li>";
				}
				$str.= "</ul>";
			}
		}
		return $str;
		
    }
    
	/**
     * Method to validate a field in the form
     *
     * @param string $name
     * @param string $value
     * @access private
     * @return bool true if field is valid, false if not
     */		    
    private function validateField($name, $value) {
    
		$value = trim($value);
		if ($this->_arrFields[$name]['required'] && empty($value)) {
			$this->_arrErrors[] = "The field " . $name . " is required.";
			return false;
		}
		if (
			isset($this->_arrFields[$name]['rule']) && 
			!empty($this->_arrFields[$name]['rule']) && 
			!call_user_func(array($this,$this->_arrFields[$name]['rule']),$this->_data[$name])
		) {
			$this->_arrErrors[] = "The field ".$name." is not valid !";
			return false;
		} else {
			if (!empty($value)) {
				if ($this->_arrFields[$name]['type'] == 'select') {
					$this->_arrSucces[] = strtolower($this->_arrFields[$name]['label'])." : ".$this->_arrFields[$name]['options'][$value];
				} else {
					$this->_arrSucces[] = strtolower($this->_arrFields[$name]['label'])." : ".$value;
				}
			}
			return true;				
		}
		
	}
    
    /**
     * Method to check if it's a string without numbers
     *
     * @param string $name
     * @access private
     * @return bool true if string is valid, false if not
     */		    
    private function validateName($name) {
    
		if (ereg("[0-9]+",$name)) {
			return false;
		} else {
			return true;
		}
		
	}
    
	/**
     * Method to check if it's a validate email address
     *
     * @param string $mail
     * @access private
     * @return bool true if field is valid, false if not
     */		    
    private function validateMail($mail) {
    
		if (filter_var($mail,FILTER_VALIDATE_EMAIL)) {
			return true;
		} else {
			return false;
		}
			    	
    }
    
	/**
     * Method to save a valid post of the form on a database using 4 differents drivers : mysql, db, mdb2 and dataobject
     *
     * @access public
     * @param string $driver
     * @param array $options
     * @param string $tablename
     * @return bool 
     */	
    public function saveForm($driver, $options = null, $tablename = "") {
    
    	switch ($driver) {
    	
    		case "mysql" :
	    		if (empty($options)) {
	    			trigger_error("Connection Options Array is Empty !", E_USER_ERROR);
	    			return false; 
	    		}    		
	    		if (sizeof($options) > 1) {
					if (!mysql_connect($options["hostname"], $options["login"], $options["password"])) {
						trigger_error("Connection Failed", E_USER_ERROR);
						return false;
					}
					if (!mysql_select_db($options["dbname"])) {
						trigger_error("Wrong DB Name", E_USER_ERROR);
						return false;
					}
	    		}
	    		$data = mysql_query("SHOW TABLES");
	    		if (!$data) {
	    			trigger_error("Not Connected", E_USER_ERROR);
	    			return false;
	       		}
	    		$tablenames = array();
	    		while ($row = mysql_fetch_array($data)) {
	    			$tablenames[] = $row[0] ;
	    		}
				if (empty($tablename) || !in_array($tablename, $tablenames)) {
					trigger_error("Table ".$tablename." does not exist", E_USER_ERROR);
					return false;
				}    		
				$sql_field_names = "";
				$sql_field_values = "";
				$nb_fields = sizeof($this->_arrFields);
				reset($this->_arrFields);
				for ($i=1; $i<=$nb_fields; $i++) {
					$sql_field_names .= key($this->_arrFields);
					$sql_field_values .= "'".mysql_real_escape_string($this->_data[key($this->_arrFields)])."'";
					if($i != $nb_fields) {
						$sql_field_names .= ", ";
						$sql_field_values .= ", ";
					}
					next($this->_arrFields);
				}
				$sql  = "INSERT INTO ";
				$sql .= $tablename;
				$sql .= " (";
				$sql .= $sql_field_names;
				$sql .= ") ";
				$sql .= "VALUES (";
				$sql .= $sql_field_values;					
				$sql .= ")";			
				$query = mysql_query($sql);
				if (!$query) {
					trigger_error("Query Failed", E_USER_ERROR);
					return false;
				} else {
					return true;
				}					
	    	break;
	    	
	    	case "db" :
		    	$db = $options;
		    	if (PEAR::isError($db)) {
		    		trigger_error($db->getDebugInfo(), E_USER_ERROR);
		    		return false; //erreur de connexion
		    	}
		    	$tablenames = $db->getCol('SHOW TABLES');
				if (empty($tablename) || !in_array($tablename, $tablenames)) {
					trigger_error("Table ".$tablename." does not exist", E_USER_ERROR);
					return false; //Table inexistante
				} else {
					$prepare_values = implode(",", array_fill(0, sizeof($this->_arrFields), "?"));
					$prepare_fields = implode(",", array_keys($this->_arrFields));
					$sth = $db->prepare("INSERT INTO ".$db->quoteIdentifier($tablename)." (".$prepare_fields.") VALUES (".$prepare_values.")");
			    	if (PEAR::isError($sth)) {
			    		trigger_error($sth->getDebugInfo(), E_USER_ERROR);
			    		return false; //Preparation échouée
			    	}
			    	$data = array_values($this->_data);
			    	$result = $db->execute($sth, $data);
			    	if (PEAR::isError($result)) {
			    		trigger_error($result->getDebugInfo(), E_USER_ERROR);
			    		return false; //exécution échouée
			    	}
			    	return true; //Requete executée
				}   		
	    	break;

	    	case "mdb2" :
		    	$mdb2 = $options;
		    	if (PEAR::isError($mdb2)) {
	    			trigger_error($mdb2->getDebugInfo(), E_USER_ERROR);
	    			return false;
				}
		    	$tablenames =& $mdb2->queryCol('SHOW TABLES');
				if (empty($tablename) || !in_array($tablename, $tablenames)) {
					trigger_error("Table ".$tablename." does not exist", E_USER_ERROR);
					return false; //Table inexistante
				} else {
					$prepare_values = implode(",", array_fill(0, sizeof($this->_arrFields), "?"));
					$prepare_fields = implode(",", array_keys($this->_arrFields));
					$sth = $mdb2->prepare("INSERT INTO ".$mdb2->quoteIdentifier($tablename)." (".$prepare_fields.") VALUES (".$prepare_values.")");
			    	if (PEAR::isError($sth)) {
			    		trigger_error($sth->getDebugInfo(), E_USER_ERROR);
			    		return false; //Preparation échouée
			    	}
			    	$data = array_values($this->_data);
			    	$result = $sth->execute($data);
			    	if (PEAR::isError($result)) {
			    		trigger_error($result->getDebugInfo(), E_USER_ERROR);
			    		return false; //exécution échouée
			    	}
			    	return true; //Requete executée
				}
	    	break;
	    	
	    	case "DataObject" :
	    	$do = $options;
	    		$do->setFrom($this->_data);
	    		$do->insert();
	    	break;
	    	
	    	default :
	    		return false;
	    	break;
	    	
    	}
    
    }

	/**
     * Method to send an email containing the result of a valid post of the form 
     *
     * @param string $mail
     * @param string $subject
     * @access public
     * @return void
     */		        
    public function sendByMail($mail, $subject = "Form Result") {
    
    	if (!$this->validateMail($mail)) {
    		return false;
    	} else {
    		$message = var_export($this->getRawResult(), true);
    		$resmail = mail($mail, $subject, $message);
    		if (!$resmail) {
    			echo 'erreur mail';
    		} else {
    			echo $message;
    		}
    	}
    
    }
    
	/**
     * Method to put the result of an array in the private property $_data
     *
     * @param array $data
     * @access public
     * @return void
     */		        
    public function setFrom($data) {
    
    	$this->_data = $data;
    	
    }
    
    /**
     * Method to get if a field is valid or not
     *
     * @access public
     * @return bool
     */		        
    public function validate() {
    
    	if (!empty($this->_data)) {
			foreach($this->_arrFields as $name => $rules) {
				if (!isset($this->_data[$name])) {
					$this->_data[$name] = "";
				}
				$this->validateField($name, $this->_data[$name]);
			}
			if (!empty($this->_arrErrors)) {
				return false;
			} else {
				return true;
			}
		} else {
			return false;
		}
		
    }
    
    /**
     * Method to get the form
     *
     * @access public
     * @return string
     */		           
    public function getForm() {
    
    	$errors_block_display = "none";
    	if (!$this->_getActiveJs() && !empty($this->_arrErrors)) {
    		$errors_block_display = "block";
    	}    
    	$form = '<div id="container">
    				<h1 id="logo"><a href="http://wufoo.com">Wufoo</a></h1>
					<form id="contactform" class="wufoo topLabel" method="post" onsubmit="return validateForm(this);">
						<div class="info">
							<h2>Contact Form</h2>
							<div>Fill Your Personal Informations :</div>
						</div>			
						<ul>
							<li id="errorLi" style="display:'.$errors_block_display.'">
								<h3 id="errorMsgLbl">There was a problem with your submission. !</h3>
								<p id="errorMsg"></p>
							</li>';
		foreach ($this->_arrFields as $name => $rules) {
			if ($rules['required']) {					
				$req_sign = '<span class="req">*</span>';
			} else {
				$req_sign = "";
			}
			if (!empty($this->_data[$name])) {
				$field = $this->_getField($rules['type'], $name, $rules['required'], $rules['rule'], $rules['options'], $this->_data[$name]);
			} else {
				$field = $this->_getField($rules['type'], $name, $rules['required'], $rules['rule'],$rules['options']);
			}
			$form .= '<li class="formrow ">';
			$form .= '<label for="'.$name.'" class="desc">'.$rules['label'].' '.$req_sign.'</label>';
			$form .= '<div class="fieldcontainer">'.$field.'</div>';
			$form .= '<p id="'.$name.'_error" class="error"></p>';
			$form .= '</li>';
		}
		$form .= '<li class="buttons">
					<input class="btTxt submit" type="submit" value="Ok" /> 
					<input class="btTxt reset" type="reset" value="Annuler" />
				</li>
			</ul>
		</form>';
		$form .= '<script>'.$this->loadJs().'</script>';			
		return $form;
		
	}
	
	/**
     * Method to display the form
     *
     * @access public
     * @return void
     */		        
	public function displayForm() {
	
		echo $this->getForm();
		
	}
	
	/**
     * Method to display the result of the form's post
     *
     * @access public
     * @return string
     */		        	
	public function displayResult() {
	
		$retour = '';
		$retour .= '<div id="container">
    					<h1 id="logo"><a href="http://wufoo.com">Wufoo</a></h1>
    					<div id="result">';
		$retour .= $this->getResult();
		$retour .= '</div></div>';
		echo $retour;
		
	}
		
}
?>
Return current item: Skunky Form