<?PHP
/**
 * Gathers wrappers for handling inputs.
 */
declare(strict_types = 1);

/**
 * Standard class providing overrides of default PHP functions as static
 * functions.
 */
final class MD_STD_IN {

    /**
     * Validates and sanitizes input integers to be in line with MySQL
     * autoincrement IDs.
     *
     * @param mixed $input Input string.
     *
     * @return integer
     */
    public static function sanitize_id($input):int {

        $input = \filter_var($input, \FILTER_VALIDATE_INT, [
                'options' => [
                    'min_range' => 1,           // Minimum number of an ID generated.
                    'max_range' => 4294967295   // Max value for MySQL's int data type
                ],
            ]
        );

        if (!($input)) {
            throw new MDpageParameterNotNumericException("Value is not numeric.");
        }

        return $input;

    }

    /**
     * Sanitizes and validates input integers to be either valid IDs or 0.
     *
     * @param mixed $input Input string.
     *
     * @return integer
     */
    public static function sanitize_id_or_zero($input):int {

        if ($input === "") return 0;

        $input = \filter_var($input, \FILTER_VALIDATE_INT, [
                'options' => [
                    'min_range' => 0,           // Minimum number of an ID generated.
                    'max_range' => 4294967295   // Max value for MySQL's int data type
                ],
            ]
        );

        if ($input === false) {
            throw new MDpageParameterNotNumericException("Value is not numeric.");
        }

        return $input;

    }

    /**
     * General string sanitization for all purposes. For use of inputs with MySQL's
     * MATCH AGAINST, use the dedicated sanitization function.
     *
     * @param mixed $input Input string.
     *
     * @return string
     */
    public static function sanitize_text($input):string {

        $output = \filter_var($input,
            FILTER_SANITIZE_STRING,
            FILTER_FLAG_NO_ENCODE_QUOTES);

        if ($output === false) return "";
        while (strpos($output, "  ") !== false) {
            $output = str_replace("  ", " ", $output);
        }

        return trim($output);

    }

    /**
     * Retrieves HTTP input texts from GET or POST variables, whatever is provided.
     * If neither is given, returns a provided default.
     *
     * @param string        $var_name Variable name.
     * @param string        $default  Default value for the output.
     * @param array<string> $allowed  List of allowed values. Defaults to empty (all values allowed).
     *
     * @return string
     */
    public static function get_http_input_text(string $var_name, string $default = "", array $allowed = []):string {

        if (isset($_GET[$var_name])) {
            $output = self::sanitize_text($_GET[$var_name]);
        }
        else if (isset($_POST[$var_name])) {
            $output = self::sanitize_text($_POST[$var_name]);
        }
        else $output = self::sanitize_text($default);

        if (!empty($allowed) and !\in_array($output, $allowed, true)) {
            Throw new MDpageParameterNotFromListException("Parameter `{$var_name}` must be any of the allowed values: '" . implode('\', \'', $allowed) . "'");
        }

        return $output;

    }

    /**
     * Retrieves HTTP input texts from POST variables.
     * If none is given, returns a provided default.
     *
     * @param string        $var_name Variable name.
     * @param string        $default  Default value for the output.
     * @param array<string> $allowed  List of allowed values. Defaults to empty (all values allowed).
     *
     * @return string
     */
    public static function get_http_post_text(string $var_name, string $default = "", array $allowed = []):string {

        if (isset($_POST[$var_name])) {
            $output = self::sanitize_text($_POST[$var_name]);
        }
        else $output = self::sanitize_text($default);

        if (!empty($allowed) and !\in_array($output, $allowed, true)) {
            Throw new MDpageParameterNotFromListException("Parameter `{$var_name}` must be any of the allowed values: '" . implode('\', \'', $allowed) . "'");
        }

        return $output;

    }

    /**
     * Sanitizes and validates a URL. An empty string passes.
     *
     * @param mixed $input Input string.
     *
     * @return string
     */
    public static function sanitize_url($input):string {

        if ($input === "") return "";

        $output = \filter_var($input, FILTER_SANITIZE_URL);
        if (($output = \filter_var($output, FILTER_VALIDATE_URL)) === false) {
            throw new MDInvalidUrl("Invalid input URL");
        }

        return $output;

    }

    /**
     * Sanitizes and validates an e-mail address. An empty string passes.
     *
     * @param mixed $input Input string.
     *
     * @return string
     */
    public static function sanitize_email($input):string {

        if ($input === "") return "";

        $output = \filter_var($input, FILTER_SANITIZE_EMAIL);
        if (($output = \filter_var($output, FILTER_VALIDATE_EMAIL)) === false) {
            throw new MDInvalidEmail("Invalid input email address");
        }

        return $output;

    }

    /**
     * Sanitizes a string to a float.
     *
     * @param string $input Input string.
     *
     * @return float
     */
    public static function sanitize_float(string $input):float {

        $output = \str_replace(",", ".", $input);
        if (($output = \filter_var($output, FILTER_VALIDATE_FLOAT)) === false) {
            throw new MDgenericInvalidInputsException("Input is readable as a floating point value");
        }
        return $output;

    }

    /**
     * Validates ISBNs. Empty strings are accepted as well.
     *
     * @param string $input Input string.
     *
     * @return string
     */
    public static function validate_isbn(string $input):string {

        if ($input === "") return "";

        // Remove hyphens
        $input = trim(strtr($input, ["-" => "", "–" => ""]));

        // ISBN 10
        if (\mb_strlen($input) === 10) {

            if (\preg_match('/\d{9}[0-9xX]/i', $input)) {
                return $input;
            }

        }

        // ISBN 13
        if (\mb_strlen($input) === 10) {

            if (\preg_match('/\d{13}/i', $input)) {
                return $input;
            }

        }

        throw new MDgenericInvalidInputsException("ISBNs must be either 10 or 13 characters long.");

    }

}