<?php
/**
* @file form2.class.php
* @author Ferenc Szontágh <szontagh.ferenc@gmail.com>
*
* @section LICENSE
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* @section DESCRIPTION
*
* Generate Programmatically HTML forms with PHP<br/>
* Tested on PHP 5.5.12 with HTML5<br/>
* Compatible with <a href="http://getbootstrap.com/">Bootstrap</a>
*
*/
class form2 {
/**
* Variable to store the form_name
*/
private $form_name;
/**
* object list with the added inputs
*/
private $forms;
/**
* counter for internal input ids
*/
private $counter = 0;
/**
* generate auto input id, or use the users's
*/
private $auto_id = true;
/**
* the method of the form
*/
private $method = "POST";
/**
* Append to the current div container
*/
private $append = false;
/**
* collected from $_POST
*/
private $_post;
/**
* collected from $_GET
*/
private $_get;
/**
*
* name: form2::__construct
* Constructor for set up the default values
* @param $form_name The name of the form
* @param $method The method of the form
* @param $auto_id TRUE: Generate auto input id, FALSE: do not generate auto id
* @return void
*
*/
function __construct($form_name = null, $method = "POST", $auto_id = true) {
$this->auto_id = $auto_id;
$this->form_name = $form_name;
// if no form name present, then we generate a one
if ($this->form_name === null) {
$this->form_name = md5(date("Y"));
}
$this->method = $method;
$this->_get = $_GET;
$this->_post = $_POST;
}
/**
*
* name: form2::addResetButton
* Add a reset button to the form, alias to form2::addInput method with predefined parameters
* @param $name Name of the reset button
* @param $label The string of the button
* @return object form_input The reset button object
*
*/
public function addResetButton($name, $label) {
return $this->addInput("reset", $name, null, $label, null);
}
/**
*
* name: form2::addButton
* Add a button to the form, alias to form2::addInput method with predefined parameters
* @param $name The name of the button
* @param $label The string of the button
* @return object form_input The button object
*
*/
public function addButton($name, $label) {
return $this->addInput("button", $name, null, $label, null);
}
/**
*
* name: form2::addInput
* Add a new input to the form
* @param $type The type of the input
* @param $name The name of the input
* @param $label String into the label tag, if omitted, no label generated
* @param $value The default value of the input, if omitted, no value added
* @param $id The input id
* @return object form_input The input object
*
*/
public function addInput($type, $name, $label = null, $value = null, $id = null) {
if ($id === null AND $this->auto_id === true) {
$id = $this->form_name . "_" . $name + "_" . md5($this->counter);
}
$this->forms[$this->counter] = new form_input($type, $name, $value, $id);
if ($title !== null) {
$this->forms[$this->counter]->addAttr("title", $label);
}
$last_id = $this->counter;
$this->counter++;
return $this->forms[$last_id];
}
/**
*
* name: form2::show
* Render & show the generated form
* @return string Return the generated HTML Form
*
*/
public function show() {
return $this->render();
}
/**
*
* name: form2::render
* Render the html from the added forms
* @return string Return the generated HTML Form
*
*/
private function render() {
$ret = "\n<form role=\"form\" method=\"" . $this->method . "\" name=\"" . $this->form_name . "\">";
$show_separator = true;
$types = new input_types();
foreach ($this->forms as $form_id => $form) {
$previous = isset($this->forms[($form_id - 1)]) ? $this->forms[($form_id - 1)] : null;
$prev_is_button = $previous === null ? false : ($types->isButton($previous->type));
$next = isset($this->forms[($form_id + 1)]) ? $this->forms[($form_id + 1)] : null;
$next_is_button = $next === null ? false : ($types->isButton($next->type));
$current_is_button = $types->isButton($form->type);
if ($prev_is_button === false AND $current_is_button === true) {
$ret .= "\t</div>";
}
if (($prev_is_button === false AND $current_is_button === true) OR $current_is_button === false) {
if ($form->type == "radio" OR $form->type == "checkbox") {
$ret .= "\n\t<div class=\"" . $form->type . "\">";
} else {
$ret .= "\n\t<div class=\"form-group\">";
}
}
$ret .= "\n\t\t\t" . $form->get() . "\n";
if ($next_is_button === false) {
$ret .= "\t</div>";
}
}
$ret .= "\n</form>";
return $ret;
}
/**
*
* name: form2::validate
* Validate the forms value with the specified rules
* @return bool Return true, when all form is filled with correct values
*
*/
public function validate() {
$type = new input_types();
if (count($this->_post) < 1) {
return false;
}
foreach ($this->forms as $form_id => $form) {
if ($type->isButton($form->type)) {
continue;
}
if (!isset($form->validate->type)) {
switch ($form->type) {
case "email":
$this->forms[$form_id]->addRule("regex", "/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/", "INVALID_EMAIL");
break;
case "number":
$this->forms[$form_id]->addRule("regex", "/^[0-9]+$/", "INVALID_NUMBER");
break;
case "datetime":
case "datetime-local":
$this->forms[$form_id]->addRule("regex", "/^([0-9]{4}\.\ [0-9]{2}\.\ [0-9]{2}\.\ [\d]{2}\:[\d]{2})$/", "INVALID_DATETIME_FORMAT");
break;
}
}
if (isset($this->_post[$form->name])) {
if ($form->type != "select" AND $form->type != "radio" AND $form->type != "checkbox") {
$form->value = $this->_post[$form->name];
}
if ($form->type == "select" and isset($this->_post[$form->name])) {
$form->addAttr("selected", $this->_post[$form->name]);
}
if (($form->type == "radio" or $form->type == "checkbox") and isset($this->_post[$form->name])) {
if ($form->value == $this->_post[$form->name]) {
$form->addAttr("checked", "checked");
}
}
}
}
$status = null;
foreach ($this->forms as $form_id => $form) {
if ($type->isButton($form->type)) {
continue;
}
if (isset($form->validate->type)) {
switch ($form->validate->type) {
case "regex":
$check = preg_match($form->validate->context, $form->value, $t);
$check = $check == 1 ? true : false;
break;
case "callback":
$check = call_user_func($form->validate->context, $form->value);
break;
default:
$check = true;
}
if ($check === true AND $form->valid !== false) {
$form->valid = true;
} else {
$form->valid = false;
$form->error_str = $form->validate->error_str;
}
}
if ($form->getAttr("minlength") !== null) {
if (mb_strlen($form->value) < $form->getAttr("minlength")) {
$form->valid = false;
$form->error_str = "MIN_LENGTH";
} else {
if ($form->valid === null) {
$form->valid = true;
}
}
}
if ($form->getAttr("maxlength") !== null) {
if (mb_strlen($form->value) > $form->getAttr("maxlength")) {
$form->valid = false;
$form->error_str = "MAX_LENGTH";
} else {
if ($form->valid === null) {
$form->valid = true;
}
}
}
if ($form->getAttr("required") !== null) {
if (mb_strlen($form->value) < 1) {
$form->valid = false;
$form->error_str = "REQUIERED";
} else {
if ($form->valid === null) {
$form->valid = true;
}
}
}
if ($form->getAttr("min") != null) {
if ($form->value < $form->getAttr("min")) {
$form->valid = false;
$form->error_str = "NUM_LOWER_THAN_MIN";
} else {
if ($form->valid === null) {
$form->valid = true;
}
}
}
if ($form->getAttr("max") != null) {
if ($form->value > $form->getAttr("max")) {
$form->valid = false;
$form->error_str = "NUM_HIGHER_THAN_MAX";
} else {
if ($form->valid === null) {
$form->valid = true;
}
}
}
if ($form->valid === false) {
$status = false;
}
if ($status === null AND $form->valid === true) {
$status = true;
}
}
return $status;
}
}
/**
*
* Object for store and manipulate input elements
*
*/
class form_input {
/**
* type of the input
*/
public $type;
/**
* name of the input
*/
public $name;
/**
* value of the input
*/
public $value;
/**
* id of the input
*/
public $id;
/**
* object for store the validate info for the input
*/
public $validate = null;
/**
* other attributes for the input
*/
private $attrs;
/**
* defult class for inputs
*/
private $default_input_class = "form-control";
/**
* default class for buttons
*/
private $default_button_class = "btn btn-default";
/**
* default class for reset buttons
*/
private $default_button_reset_class = "btn btn-danger";
/**
* validated state of the input
*/
public $valid = null;
/**
* error string for the input
*/
public $error;
/**
*
* name: form_input::__construct
* Construct default parameters
* @param $type Type of the input
* @param $name Name of the input
* @param $value Value of the input
* @param $id Id of the input
*
*/
function __construct($type, $name, $value, $id) {
$this->type = $type;
$this->name = $name;
$this->value = $value;
$this->id = $id;
$this->attrs = new stdClass();
$this->validate = new stdClass();
}
/**
*
* name: form_input::addAttr
* Add attribute to the element
* @param $key name of the attribute, if is array, then the form_input::$value can be omitted
* @param $value value of the attribute
*
*/
public function addAttr($key, $value = null) {
if (is_array($key) AND $value === null) {
foreach ($key as $k => $v) {
$this->attrs->$k = $v;
}
} else {
$this->attrs->$key = $value;
}
}
/**
*
* name: form_input::removeAttr
* Remove attribute from the input
* @param $key Name of the attribute to remove
*
*/
public function removeAttr($key) {
if (isset($this->attrs->$key)) {
unset($this->attrs->$key);
}
}
/**
*
* name: form_input::getAttr
* Return the value of the input attribute, or null when the attribute not found
* @param $key Name of the attribute
* @return string Return the value of the attribute
*
*/
public function getAttr($key) {
if (isset($this->attrs->$key)) {
return $this->attrs->$key;
}
return null;
}
/**
*
* name: form_input::get
* Return the full formatted html input
* @return string Return the html output of the input
*
*/
public function get() {
$type = new input_types();
if (!isset($this->attrs->class) OR $this->attrs->class == null) {
if ($type->isLineInput($this->type)) {
$this->addAttr("class", $this->default_input_class);
}
if ($this->type == "button" or $this->type == "submit" or $this->type == "link") {
$this->addAttr("class", $this->default_button_class);
}
if ($this->type == "reset") {
$this->addAttr("class", $this->default_button_reset_class);
}
}
$d = "";
if ($this->getAttr("title") !== null AND $type->isButton($this->type) === false AND ($this->type != "radio") AND $this->type != "checkbox") {
$d .= "<label for=\"" . $this->id . "\">" . $this->getAttr("title") . "</label>";
}
if ($this->type == "radio" OR $this->type == "checkbox") {
$d .= "<label for=\"" . $this->id . "\">";
}
switch ($this->type) {
case "select":
$d .= "<select name=\"" . $this->name . "\"";
if (isset($this->id)) {
$d .= " id=\"" . $this->id . "\"";
}
break;
case "textarea":
$d .= "<textarea";
break;
case "button":
$d .= "<button name=\"" . $this->name . "\"";
break;
default:
$d .= "<input type=\"" . $this->type . "\"";
$d .= " name=\"" . $this->name . "\"";
if (!empty($this->value)) {
$d .= " value=\"" . $this->value . "\"";
}
if (!empty($this->id)) {
$d .= " id=\"" . $this->id . "\"";
}
}
$attr = get_object_vars($this->attrs);
if (is_array($attr)) {
foreach ($attr as $k => $v) {
if ($k == "required") {
$v = $v == true ? "required" : "";
}
$d .= " " . $k . "=\"" . $v . "\" ";
}
}
switch ($this->type) {
case "textarea":
$d .= ">" . $this->value . "</textarea>";
break;
case "button":
$d .= ">" . $this->value . "</button>";
break;
case "select":
$d .= ">";
if (isset($this->value) AND !empty($this->value)) {
$selected = $this->getAttr("selected");
foreach ($this->value as $vk => $vv) {
if ($selected !== null AND $selected == $vk) {
$d .= "<option selected=\"selected\" value=\"" . $vk . "\">" . $vv . "</option>";
} else {
$d .= "<option value=\"" . $vk . "\">" . $vv . "</option>";
}
}
}
$d .= "</select>";
break;
default:
$d .= "/>";
}
if ($this->type == "radio" OR $this->type == "checkbox") {
$d .= $this->getAttr("title");
$d .= "</label>";
}
if ($this->valid === false) {
$d .= "<p style='color: #FF0000'>" . $this->error_str . "</p>";
}
return $d;
}
/**
*
* name: form_input::addRule
* @param $type Type of the validate rule: regex,callback
* @param $context regex: then a regex pattern, callback: a function name
* @param $error_str The error string, when the pattern not match or the callback function return false
* @return
*
*/
public function addRule($type, $context, $error_str) {
$this->validate->type = $type;
$this->validate->context = $context;
$this->validate->error_str = $error_str;
}
}
/**
*
* Container object for storing input types
*
*/
class input_types {
private $button_inputs = array("button", "submit", "reset", "link");
private $line_inputs = array("text", "password", "datetime", "datetime-local", "date", "month", "time", "week", "number", "email", "url", "search", "tel", "color", "select");
private $hight_inputs = array("textarea", "multiselect");
/**
*
* name: input_types::getButtons
* @return array Array list of button input types
*
*/
public function getButtons() {
return $this->button_inputs;
}
/**
*
* name: input_types::getLineInputs
* @return array Array list of lined input types (like text,password)
*
*/
public function getLineInputs() {
return $this->line_inputs;
}
/**
*
* name: input_types::getHightInputs
* @return array Array list of high (tall) inputs
*
*/
public function getHightInputs() {
return $this->getHightInputs;
}
/**
*
* name: input_types::isButton
* @param $type Type name of an element
* @return bool true when it is a button, false when not
*
*/
public function isButton($type) {
return in_array($type, $this->button_inputs);
}
/**
*
* name: input_types::isLineInput
* @param $type Type name of an element
* @return bool true when it is a line input, false when not
*
*/
public function isLineInput($type) {
return in_array($type, $this->line_inputs);
}
/**
*
* name: input_types::isHightInput
* @param $type Type name of an element
* @return bool true when it is a high input, false when not
*
*/
public function isHightInput($type) {
return in_array($type, $this->hight_inputs);
}
}
?>