array( 'open_form' => '', 'open_form_body' => '', 'close_form_body' => '', 'open_field' => '', 'close_field' => '', 'open_html' => "
  • \n", 'close_html' => "
  • \n", 'open_submit' => "
  • \n", 'close_submit' => "
  • \n" ), 'table' => array( 'open_form' => '', 'close_form' => '
    ', 'open_form_body' => '', 'close_form_body' => '', 'open_field' => "\n", 'close_field' => "\n", 'open_html' => "\n", 'close_html' => "\n", 'open_submit' => '', 'close_submit' => '' ) ); protected static $instance = array(); /** * @param string $action * @param string $submit_value * @param string $method * @param boolean $sticky * @param string $message_type * @param string $format * @param string $multiple_errors * * @return NibbleForm */ public function __construct( $action, $submit_value, $html5, $method, $sticky, $message_type, $format, $multiple_errors ) { $this->fields = new \stdClass(); $this->action = $action; $this->method = $method; $this->html5 = $html5; $this->submit_value = $submit_value; $this->sticky = $sticky; $this->format = $format; $this->message_type = $message_type; $this->multiple_errors = $multiple_errors; spl_autoload_register(array($this, 'nibbleLoader')); } /** * Singleton method * * @param string $action * @param string $method * @param boolean $sticky * @param string $submit_value * @param string $message_type * @param string $format * @param string $multiple_errors * * @return NibbleForm */ public static function getInstance( $name = '', $action = '', $html5 = true, $method = 'post', $submit_value = 'Submit', $format = 'list', $sticky = true, $message_type = 'list', $multiple_errors = false ) { if (!isset(self::$instance[$name])) { self::$instance[$name] = new NibbleForm($action, $submit_value, $html5, $method, $sticky, $message_type, $format, $multiple_errors); } return self::$instance[$name]; } /** * Autoloader for nibble forms * * @param string $class */ public static function nibbleLoader($class) { $namespace = explode('\\', trim($class)); foreach ($namespace as $key => $value) { if (empty($value)) { unset($namespace[$key]); } } $filepath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $namespace) . '.php'; if (file_exists($filepath)) { require_once $filepath; } } /** * Add a field to the form instance * * @param string $field_name * @param string $type * @param array $attributes * @param boolean $overwrite * * @return boolean */ public function addField($field_name, $type = 'text', array $attributes = array(), $overwrite = false) { $namespace = "\\Nibble\\NibbleForms\\Field\\" . ucfirst($type); if (isset($attributes['label'])) { $label = $attributes['label']; } else { $label = ucfirst(str_replace('_', ' ', $field_name)); } $field_name = Useful::slugify($field_name, '_'); if (isset($this->fields->$field_name) && !$overwrite) { return false; } $this->fields->$field_name = new $namespace($label, $attributes); $this->fields->$field_name->setForm($this); return $this->fields->$field_name; } /** * Set the name of the form * * @param string $name */ public function setName($name) { $this->name = $name; } /** * Get form name * * @return string */ public function getName() { return $this->name; } /** * Get form method * * @return string */ public function getMethod() { return $this->method; } /** * Add data to populate the form * * @param array $data */ public function addData(array $data) { $this->data = array_merge($this->data, $data); } /** * Validate the submitted form * * @return boolean */ public function validate() { $request = strtoupper($this->method) == 'POST' ? $_POST : $_GET; if (isset($request[$this->name])) { $form_data = $request[$this->name]; } else { $this->valid = false; return false; } if ((isset($_SESSION["nibble_forms"]["_crsf_token"], $_SESSION["nibble_forms"]["_crsf_token"][$this->name]) && $form_data["_crsf_token"] !== $_SESSION["nibble_forms"]["_crsf_token"][$this->name]) || !isset($_SESSION["nibble_forms"]["_crsf_token"]) || !isset($form_data["_crsf_token"]) ) { $this->setMessages('CRSF token invalid', 'CRSF error'); $this->valid = false; } $_SESSION["nibble_forms"]["_crsf_token"] = array(); if ($this->sticky) { $this->addData($form_data); } foreach ($this->fields as $key => $value) { if (!$value->validate( (isset($form_data[$key]) ? $form_data[$key] : (isset($_FILES[$this->name][$key]) ? $_FILES[$this->name][$key] : '')) ) ) { $this->valid = false; return false; } } return $this->valid; } public function getData($key) { return isset($this->data[$key]) ? $this->data[$key] : false; } /** * Render the entire form including submit button, errors, form tags etc * * @return string */ public function render() { $fields = ''; $error = $this->valid ? '' : '

    Sorry there were some errors in the form, problem fields have been highlighted

    '; $format = (object) $this->formats[$this->format]; $this->setToken(); foreach ($this->fields as $key => $value) { $format = (object) $this->formats[$this->format]; $temp = isset($this->data[$key]) ? $value->returnField($this->name, $key, $this->data[$key]) : $value->returnField($this->name, $key); $fields .= $format->open_field; if ($temp['label']) { $fields .= $format->open_html . $temp['label'] . $format->close_html; } if (isset($temp['messages'])) { foreach ($temp['messages'] as $message) { if ($this->message_type == 'inline') { $fields .= "$format->open_html

    $message

    $format->close_html"; } else { $this->setMessages($message, $key); } if (!$this->multiple_errors) { break; } } } $fields .= $format->open_html . $temp['field'] . $format->close_html . $format->close_field; } if (!empty($this->messages)) { $this->buildMessages(); } else { $this->messages = false; } self::$instance = false; $attributes = $this->getFormAttributes(); return <<
    messages $format->open_form $format->open_form_body $fields $format->close_form_body $format->open_submit $format->close_submit $format->close_form
    FORM; } /** * Returns the HTML for a specific form field ususally in the form of input tags * * @param string $name * * @return string */ public function renderField($name) { return $this->getFieldData($name, 'field'); } /** * Returns the HTML for a specific form field's label * * @param string $name * * @return string */ public function renderLabel($name) { return $this->getFieldData($name, 'label'); } /** * Returns the error string for a specific form field * * @param string $name * * @return string */ public function renderError($name) { $error_string = ''; if (!is_array($this->getFieldData($name, 'messages'))) { return false; } foreach ($this->getFieldData($name, 'messages') as $error) { $error_string .= "
  • $error
  • "; } return $error_string === '' ? false : ""; } /** * Returns the boolean depending on existance of errors for specified * form field * * @param string $name * * @return boolean */ public function hasError($name) { $errors = $this->getFieldData($name, 'messages'); if (!$errors || !is_array($errors)) { return false; } return true; } /** * Returns the entire HTML structure for a form field * * @param string $name * * @return string */ public function renderRow($name) { $row_string = $this->renderError($name); $row_string .= $this->renderLabel($name); $row_string .= $this->renderField($name); return $row_string; } /** * Returns HTML for all hidden fields including crsf protection * * @return string */ public function renderHidden() { $this->setToken(); $fields = array(); foreach ($this->fields as $name => $field) { if (get_class($field) == 'Nibble\\NibbleForms\\Field\\Hidden') { if (isset($this->data[$name])) { $field_data = $field->returnField($this->name, $name, $this->data[$name]); } else { $field_data = $field->returnField($this->name, $name); } $fields[] = $field_data['field']; } } return implode("\n", $fields); } /** * Returns HTML string for all errors in the form * * @return string */ public function renderErrors() { $error_string = ''; foreach (array_keys($this->fields) as $name) { foreach ($this->getFieldData($name, 'messages') as $error) { $error_string .= "
  • $error
  • \n"; } } return $error_string === '' ? false : ""; } /** * Returns the HTML string for opening a form with the correct enctype, action and method * * @return string */ public function openForm() { $attributes = $this->getFormAttributes(); return "
    action\" method=\"$this->method\" {$attributes['enctype']} {$attributes['html5']}>"; } /** * Return close form tag * * @return string */ public function closeForm() { return "
    "; } /** * Check if a field exists * * @param string $field * * @return boolean */ public function checkField($field) { return isset($this->fields->$field); } /** * Get the attributes for the form tag * * @return array */ private function getFormAttributes() { $enctype = ''; foreach ($this->fields as $field) { if (get_class($field) == 'File') { $enctype = 'enctype="multipart/form-data"'; } } $html5 = $this->html5 ? '' : 'novalidate'; return array( 'enctype' => $enctype, 'html5' => $html5 ); } /** * Adds a message string to the class messages array * * @param string $message * @param string $title */ private function setMessages($message, $title) { $title = preg_replace('/_/', ' ', ucfirst($title)); if ($this->message_type == 'list') { $this->messages[] = array('title' => $title, 'message' => ucfirst($message)); } } /** * Sets the messages array as an HTML string */ private function buildMessages() { $messages = ''; } /** * Gets a specific field HTML string from the field class * * @param string $name * @param string $key * * @return string */ private function getFieldData($name, $key) { if (!$this->checkField($name)) { return false; } $field = $this->fields->$name; if (isset($this->data[$name])) { $field = $field->returnField($this->name, $name, $this->data[$name]); } else { $field = $field->returnField($this->name, $name); } return $field[$key]; } /** * Creates a new CRSF token * * @return string */ private function setToken() { if (!isset($_SESSION["nibble_forms"])) { $_SESSION["nibble_forms"] = array(); } if (!isset($_SESSION["nibble_forms"]["_crsf_token"])) { $_SESSION["nibble_forms"]["_crsf_token"] = array(); } $_SESSION["nibble_forms"]["_crsf_token"][$this->name] = Useful::randomString(20); $this->addField("_crsf_token", "hidden"); $this->addData(array("_crsf_token" => $_SESSION["nibble_forms"]["_crsf_token"][$this->name])); } }