summaryrefslogblamecommitdiffstats
path: root/app/class/form.class.php
blob: 10a68c39e0d62e1df8d3ec6f212fae7fa037e522 (plain) (tree)



























































































































































                                                                                                 
                                              





















                                                                                     
<?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);
    }
}

?>