configure(array( "action" => basename($_SERVER["SCRIPT_NAME"]), "id" => preg_replace("/\W/", "-", $id), "method" => "post" )); if(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") $this->_prefix = "https"; /*The Standard view class is applied by default and will be used unless a different view is specified in the form's configure method*/ if(empty($this->view)) $this->view = new View\SideBySide; if(empty($this->errorView)) $this->errorView = new ErrorView\Standard; /*The resourcesPath property is used to identify where third-party resources needed by the project are located. This property will automatically be set properly if the PFBC directory is uploaded within the server's document root. If symbolic links are used to reference the PFBC directory, you may need to set this property in the form's configure method or directly in this constructor.*/ $path = __DIR__ . "/Resources"; if(strpos($path, $_SERVER["DOCUMENT_ROOT"]) !== false) $this->resourcesPath = substr($path, strlen($_SERVER["DOCUMENT_ROOT"])); else $this->resourcesPath = "/PFBC/Resources"; } /*When a form is serialized and stored in the session, this function prevents any non-essential information from being included.*/ public function __sleep() { return array("_attributes", "_elements", "errorView"); } public function addElement(Element $element) { $element->_setForm($this); //If the element doesn't have a specified id, a generic identifier is applied. $id = $element->getAttribute("id"); if(empty($id)) $element->setAttribute("id", $this->_attributes["id"] . "-element-" . sizeof($this->_elements)); $this->_elements[] = $element; /*For ease-of-use, the form tag's encytype attribute is automatically set if the File element class is added.*/ if($element instanceof Element\File) $this->_attributes["enctype"] = "multipart/form-data"; } /*Values that have been set through the setValues method, either manually by the developer or after validation errors, are applied to elements within this method.*/ protected function applyValues() { foreach($this->_elements as $element) { $name = $element->getAttribute("name"); if(isset($this->_values[$name])) $element->setAttribute("value", $this->_values[$name]); elseif(substr($name, -2) == "[]" && isset($this->_values[substr($name, 0, -2)])) $element->setAttribute("value", $this->_values[substr($name, 0, -2)]); } } public static function clearErrors($id = "pfbc") { if(!empty($_SESSION["pfbc"][$id]["errors"])) unset($_SESSION["pfbc"][$id]["errors"]); } public static function clearValues($id = "pfbc") { if(!empty($_SESSION["pfbc"][$id]["values"])) unset($_SESSION["pfbc"][$id]["values"]); } public function getAjax() { return $this->ajax; } public function getElements() { return $this->_elements; } public function getErrorView() { return $this->errorView; } public function getPrefix() { return $this->_prefix; } public function getPrevent() { return $this->prevent; } public function getResourcesPath() { return $this->resourcesPath; } public function getErrors() { $errors = array(); if(session_id() == "") $errors[""] = array("Error: The pfbc project requires an active session to function properly. Simply add session_start() to your script before any output has been sent to the browser."); else { $errors = array(); $id = $this->_attributes["id"]; if(!empty($_SESSION["pfbc"][$id]["errors"])) $errors = $_SESSION["pfbc"][$id]["errors"]; } return $errors; } protected static function getSessionValues($id = "pfbc") { $values = array(); if(!empty($_SESSION["pfbc"][$id]["values"])) $values = $_SESSION["pfbc"][$id]["values"]; return $values; } public static function isValid($id = "pfbc", $clearValues = true) { $valid = true; /*The form's instance is recovered (unserialized) from the session.*/ $form = self::recover($id); if(!empty($form)) { if($_SERVER["REQUEST_METHOD"] == "POST") $data = $_POST; else $data = $_GET; /*Any values/errors stored in the session for this form are cleared.*/ self::clearValues($id); self::clearErrors($id); /*Each element's value is saved in the session and checked against any validation rules applied to the element.*/ if(!empty($form->_elements)) { foreach($form->_elements as $element) { $name = $element->getAttribute("name"); if(substr($name, -2) == "[]") $name = substr($name, 0, -2); /*The File element must be handled differently b/c it uses the $_FILES superglobal and not $_GET or $_POST.*/ if($element instanceof Element\File) $data[$name] = $_FILES[$name]["name"]; if(isset($data[$name])) { $value = $data[$name]; if(is_array($value)) { $valueSize = sizeof($value); for($v = 0; $v < $valueSize; ++$v) $value[$v] = stripslashes($value[$v]); } else $value = stripslashes($value); self::_setSessionValue($id, $name, $value); } else $value = null; /*If a validation error is found, the error message is saved in the session along with the element's name.*/ if(!$element->isValid($value)) { self::setError($id, $element->getErrors(), $name); $valid = false; } } } /*If no validation errors were found, the form's session values are cleared.*/ if($valid) { if($clearValues) self::clearValues($id); self::clearErrors($id); } } else $valid = false; return $valid; } /*This method restores the serialized form instance.*/ protected static function recover($id) { if(!empty($_SESSION["pfbc"][$id]["form"])) return unserialize($_SESSION["pfbc"][$id]["form"]); else return ""; } public function render($returnHTML = false) { if(!empty($this->labelToPlaceholder)) { foreach($this->_elements as $element) { $label = $element->getLabel(); if(!empty($label)) { $element->setAttribute("placeholder", $label); $element->setLabel(""); } } } $this->view->_setForm($this); $this->errorView->_setForm($this); /*When validation errors occur, the form's submitted values are saved in a session array, which allows them to be pre-populated when the user is redirected to the form.*/ $values = self::getSessionValues($this->_attributes["id"]); if(!empty($values)) $this->setValues($values); $this->applyValues(); if($returnHTML) ob_start(); $this->renderCSS(); $this->view->render(); $this->renderJS(); /*The form's instance is serialized and saved in a session variable for use during validation.*/ $this->save(); if($returnHTML) { $html = ob_get_contents(); ob_end_clean(); return $html; } } /*When ajax is used to submit the form's data, validation errors need to be manually sent back to the form using json.*/ public static function renderAjaxErrorResponse($id = "pfbc") { $form = self::recover($id); if(!empty($form)) $form->errorView->renderAjaxErrorResponse(); } protected function renderCSS() { $this->renderCSSFiles(); echo ''; } protected function renderCSSFiles() { $urls = array(); if(!in_array("bootstrap", $this->prevent)) $urls[] = $this->_prefix . "://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css"; foreach($this->_elements as $element) { $elementUrls = $element->getCSSFiles(); if(is_array($elementUrls)) $urls = array_merge($urls, $elementUrls); } /*This section prevents duplicate css files from being loaded.*/ if(!empty($urls)) { $urls = array_values(array_unique($urls)); foreach($urls as $url) echo ''; } } protected function renderJS() { $this->renderJSFiles(); echo ''; } protected function renderJSFiles() { $urls = array(); if(!in_array("jQuery", $this->prevent)) $urls[] = $this->_prefix . "://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"; if(!in_array("bootstrap", $this->prevent)) $urls[] = $this->_prefix . "://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"; foreach($this->_elements as $element) { $elementUrls = $element->getJSFiles(); if(is_array($elementUrls)) $urls = array_merge($urls, $elementUrls); } /*This section prevents duplicate js files from being loaded.*/ if(!empty($urls)) { $urls = array_values(array_unique($urls)); foreach($urls as $url) echo ''; } } /*The save method serialized the form's instance and saves it in the session.*/ protected function save() { $_SESSION["pfbc"][$this->_attributes["id"]]["form"] = serialize($this); } /*Valldation errors are saved in the session after the form submission, and will be displayed to the user when redirected back to the form.*/ public static function setError($id, $errors, $element = "") { if(!is_array($errors)) $errors = array($errors); if(empty($_SESSION["pfbc"][$id]["errors"][$element])) $_SESSION["pfbc"][$id]["errors"][$element] = array(); foreach($errors as $error) $_SESSION["pfbc"][$id]["errors"][$element][] = $error; } protected static function _setSessionValue($id, $element, $value) { $_SESSION["pfbc"][$id]["values"][$element] = $value; } /*An associative array is used to pre-populate form elements. The keys of this array correspond with the element names.*/ public function setValues(array $values) { $this->_values = array_merge($this->_values, $values); } }