<?php
/*
* SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to UNLICENSE
*/
/*
* Model web-forms and simplify the process of accepting, validating, and
* sanitizing user input.
*/
class form
{
/*
* These arrays track the meta-data of all fields defined on this
* form. This mainly includes their type, range (if numeric), and
* whether or not the field is required.
*/
private $textFields = array();
private $numbFields = array();
private $enumFields = array();
/*
* Add new text field to this form
*/
public function text(string $name, bool $required = true,
string $deflt = "") : void
{
$this->textFields[] = array(
'name' => $name,
'required' => $required,
'default' => $deflt,
);
}
/*
* Add new numeric field to this form
*/
public function numeric(string $name, ?int $min = NULL, ?int $max = NULL,
int $deflt = 0, bool $isInt = true, bool $required = true) : void
{
$this->numbFields[] = array(
'name' => $name,
'min' => $min,
'max' => $max,
'default' => $deflt,
'isInt' => $isInt,
'required' => $required,
);
}
/*
* Add new enumeration field to this form
*/
public function enum(string $name, array $values, $deflt = NULL,
bool $required = true) : void
{
$this->enumFields[] = array(
'name' => $name,
'values' => $values,
'default' => $deflt,
'required' => $required,
);
}
/*
* Add new boolean field to this form
*/
public function flag(string $name) : void
{
$this->enum($name, array("1", "0"), "0", false);
}
/*
* Populate this form with input data from web page. If an error
* is encountered, or a required field is missing, false is returned.
*/
public function populate(array $input) : bool
{
/* detect duplicate names */
$names = array();
foreach ($this->textFields as $field)
$names[] = $field['name'];
foreach ($this->numbFields as $field)
$names[] = $field['name'];
foreach ($this->enumFields as $field)
$names[] = $field['name'];
if (count(array_unique($names)) != count($names))
throw new Exception("Internal error: Duplicate field names defined in form");
/* init text fields */
foreach ($this->textFields as $field)
{
if (isset($input[$field['name']]) && $input[$field['name']] != "")
$this->{$field['name']} = htmlentities($input[$field['name']], ENT_QUOTES);
else if ($field['required'])
logError(ERROR, $field['name'] . " is required");
else
$this->{$field['name']} = $field['default'];
}
/* init numeric fields */
foreach ($this->numbFields as $field)
{
if (isset($input[$field['name']]) && $input[$field['name']] != "")
{
if (!is_numeric($input[$field['name']]))
{
logError(ERROR, $field['name'] . " must be numeric");
continue;
}
if ($field['isInt'] && (floor($input[$field['name']]) != $input[$field['name']]))
{
logError(ERROR, $field['name'] . " must be an integer");
continue;
}
if (!is_null($field['min']) && ($input[$field['name']] < $field['min']))
{
logError(ERROR, $field['name'] . " must be no less than " . $field['min']);
continue;
}
if (!is_null($field['max']) && ($input[$field['name']] > $field['max']))
{
logError(ERROR, $field['name'] . " must be no more than " . $field['max']);
continue;
}
$this->{$field['name']} = $input[$field['name']];
}
else if ($field['required'])
logError(ERROR, $field['name'] . " is required");
else
$this->{$field['name']} = $field['default'];
}
/* init enum fields */
foreach ($this->enumFields as $field)
{
if (isset($input[$field['name']]))
{
if (array_search($input[$field['name']], $field['values']) === false)
{
logError(ERROR, $field['name'] . " is not an appropriate value");
continue;
}
$this->{$field['name']} = $input[$field['name']];
}
else if ($field['required'])
logError(ERROR, $field['name'] . " is required");
else
$this->{$field['name']} = $field['default'];
}
return !isError(ERROR);
}
}
?>