MD_STD/src/MD_STD_IN.php

347 lines
9.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?PHP
/**
* Gathers wrappers for handling inputs.
*/
declare(strict_types = 1);
/**
* Encapsulates functions for handling inputs.
*/
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(mixed $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(mixed $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(mixed $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);
}
/**
* String sanitization for 3 o4 6 characters RGB color codes (sans the leading #).
*
* @param mixed $input Input string.
*
* @return string
*/
public static function sanitize_rgb_color(mixed $input):string {
$output = \filter_var($input,
FILTER_SANITIZE_STRING,
FILTER_FLAG_NO_ENCODE_QUOTES);
if ($output === false
|| (preg_match('/^[a-zA-Z0-9]{3}$/', $output) === false && preg_match('/^[a-zA-Z0-9]{6}$/', $output) === false)
) {
throw new MDInvalidColorCode("Invalid color code provided: " . $output);
}
return $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(mixed $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(mixed $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.");
}
/**
* Returns an UTF8 version of a string.
*
* @param string $input Input string.
*
* @return string
*/
public static function ensureStringIsUtf8(string $input):string {
// If the input is valid UTF8 from the start, it is simply returned in its
// original form.
if (\mb_check_encoding($input, 'UTF-8')) {
return $input;
}
// To detect and convert the encoding for non-UTF8 strings, the list of
// encodings known to PHP's mbstring functions is checked against the input string.
// If any encoding matches the string, it will be converted to UTF8 accordingly.
$suitableEncodings = [];
$encodings = \mb_list_encodings();
foreach ($encodings as $encoding) {
if (\mb_detect_encoding($input, $encoding, true) !== false) {
$suitableEncodings[] = $encoding;
}
}
// If ISO-8859-1 is in the list of suitable encodings, try to convert with that.
if (\in_array('ISO-8859-1', $suitableEncodings, true)) {
if (($converted = \iconv('ISO-8859-1', "UTF-8//TRANSLIT", $input)) !== false) {
return $converted;
}
}
// If a conversion from ISO-8859-1 doesn't work, just take any of the other ones.
$suitableEncodings = \array_reverse($suitableEncodings);
foreach ($suitableEncodings as $encoding) {
if (($converted = \iconv($encoding, "UTF-8//TRANSLIT", $input)) !== false) {
return $converted;
}
}
/*
if (count($suitableEncodings) === 1) {
return mb_convert_encoding($input, 'UTF-8', );
}
*/
return $input;
}
/**
* Wrapper around move_uploaded_file that throws errors in case the upload failed
* for an identifiable reason.
*
* @param string $filename Name of the file to upload.
* @param string $destination Destination to move the file to.
* @param array<string> $mime_types Optional array of acceptable mime types. If this is
* not empty, the file will be checked for having one
* of the given mime types. If it does not, an error
* will be thrown.
*
* @return boolean
*/
public static function move_uploaded_file(string $filename, string $destination, array $mime_types = []):bool {
MD_STD::ensure_file($filename, $mime_types);
MD_STD::check_is_writable(dirname($destination));
if (!(\move_uploaded_file($filename, $destination))) {
return false;
}
return true;
}
}