Compare commits
17 Commits
aa7a3c5012
...
c362aa1283
Author | SHA1 | Date | |
---|---|---|---|
c362aa1283
|
|||
65aaea4097
|
|||
7c02bbb8ad
|
|||
6a7b8bd8fd
|
|||
8d7b270f6f
|
|||
9507387c8a
|
|||
589161219f
|
|||
e18b649250
|
|||
5bb863ffc9
|
|||
1b63951b44
|
|||
93991225fe
|
|||
321609306d
|
|||
2a333c1de6
|
|||
c689f7568f
|
|||
dc86540da2
|
|||
e50f1f0526
|
|||
e2ada291f7
|
@ -44,7 +44,7 @@ final class MD_STD {
|
||||
public static function realpath(string $path):string {
|
||||
|
||||
$output = \realpath($path);
|
||||
if (!\is_string($output) || empty($output)) {
|
||||
if (!\is_string($output)) {
|
||||
throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
|
||||
}
|
||||
return $output;
|
||||
@ -163,21 +163,19 @@ final class MD_STD {
|
||||
*/
|
||||
public static function startsWithAny(string $haystack, array $needles):bool {
|
||||
|
||||
$output = false;
|
||||
foreach ($needles as $needle) {
|
||||
$output = \str_starts_with($haystack, $needle);
|
||||
if ($output == true) {
|
||||
return $output;
|
||||
if (\str_starts_with($haystack, $needle) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function checking if a string contains another in a case-insensitive way.
|
||||
*
|
||||
* @param non-empty-string $haystack String to check.
|
||||
* @param string $haystack String to check.
|
||||
* @param non-empty-string $needle Potential start of $haystack.
|
||||
*
|
||||
* @return boolean
|
||||
@ -234,7 +232,7 @@ final class MD_STD {
|
||||
*
|
||||
* @param array<mixed> $value The value being encoded. Can be any type except a resource.
|
||||
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
|
||||
* @param integer $depth Depth of coding.
|
||||
* @param positive-int $depth Depth of coding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@ -253,9 +251,9 @@ final class MD_STD {
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.json-encode.php
|
||||
*
|
||||
* @param object $value The value being encoded. Can be any type except a resource.
|
||||
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
|
||||
* @param integer $depth Depth of coding.
|
||||
* @param object $value The value being encoded. Can be any type except a resource.
|
||||
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
|
||||
* @param positive-int $depth Depth of coding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@ -298,14 +296,18 @@ final class MD_STD {
|
||||
|
||||
$curl = \curl_init();
|
||||
|
||||
\curl_setopt($curl, CURLOPT_URL, $url);
|
||||
\curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
\curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, $timeout); //timeout in seconds
|
||||
\curl_setopt($curl, CURLOPT_TIMEOUT_MS, $timeout); //timeout in seconds
|
||||
\curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
// \curl_setopt($curl, CURLOPT_COOKIESESSION, true);
|
||||
\curl_setopt($curl, CURLOPT_AUTOREFERER, true);
|
||||
\curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2');
|
||||
\curl_setopt_array($curl, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_CONNECTTIMEOUT_MS => $timeout, //timeout in seconds
|
||||
CURLOPT_TIMEOUT_MS => $timeout, //timeout in seconds
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
// CURLOPT_COOKIESESSION => true,
|
||||
CURLOPT_AUTOREFERER => true,
|
||||
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2',
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
|
||||
CURLOPT_TCP_FASTOPEN => true,
|
||||
]);
|
||||
|
||||
/*
|
||||
if (!file_exists(__DIR__ . '/../../curled.txt')) {
|
||||
@ -426,6 +428,12 @@ final class MD_STD {
|
||||
}
|
||||
else {
|
||||
$lang = self::lang_getfrombrowser($allowed_langs, $default_lang, "", false);
|
||||
|
||||
// If the user is a bot or has no user agent at all or one of curl's,
|
||||
// setting a cookie usually makes little sense.
|
||||
// On the other hand, setting the cookie prevents effective caching.
|
||||
if (empty($_SERVER['HTTP_USER_AGENT']) || substr($_SERVER['HTTP_USER_AGENT'], 0, 5) === 'curl/') return $lang;
|
||||
|
||||
if (!setcookie('__Host-lang', $lang, $cookie_options)) {
|
||||
throw new Exception("Failed to set language");
|
||||
}
|
||||
@ -773,7 +781,7 @@ final class MD_STD {
|
||||
* @param array<int, int> $input Input array.
|
||||
* @param positive-int $size Size of each part of the return set.
|
||||
*
|
||||
* @return array<non-empty-array<integer>>
|
||||
* @return array<non-empty-array<int, integer>>
|
||||
*/
|
||||
public static function split_int_array_into_sized_parts(array $input, int $size):array {
|
||||
|
||||
@ -788,7 +796,36 @@ final class MD_STD {
|
||||
while ($offset < $max) {
|
||||
$cur = array_slice($input, $offset, $size - 1);
|
||||
if (!empty($cur)) $output[] = $cur;
|
||||
$offset += $size;
|
||||
$offset += $size - 1;
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits an lists of strings into parts of a predefined size and returns those
|
||||
* as sub-lists of a superordinate list.
|
||||
*
|
||||
* @param array<int, string> $input Input array.
|
||||
* @param positive-int $size Size of each part of the return set.
|
||||
*
|
||||
* @return array<non-empty-array<int, string>>
|
||||
*/
|
||||
public static function split_string_array_into_sized_parts(array $input, int $size):array {
|
||||
|
||||
/*
|
||||
if ($size < 1) throw new Exception("Size of the target array must be a positive integer");
|
||||
*/
|
||||
|
||||
$output = [];
|
||||
|
||||
$max = count($input);
|
||||
$offset = 0;
|
||||
while ($offset < $max) {
|
||||
$cur = array_slice($input, $offset, $size - 1);
|
||||
if (!empty($cur)) $output[] = $cur;
|
||||
$offset += $size - 1;
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
@ -72,7 +72,7 @@ final class MD_STD_CACHE {
|
||||
|
||||
ob_start();
|
||||
|
||||
if (($redisResult = $redis->get($redisKey))) {
|
||||
if ($redisResult = $redis->get($redisKey)) {
|
||||
|
||||
if (strlen($redisResult) > 3 and strpos($redisResult, ' id="errorPage"') === false) {
|
||||
$redis->close();
|
||||
|
@ -73,13 +73,12 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function sanitize_text(mixed $input):string {
|
||||
|
||||
$output = \filter_var($input,
|
||||
FILTER_SANITIZE_STRING,
|
||||
FILTER_FLAG_NO_ENCODE_QUOTES);
|
||||
$output = \filter_var($input, FILTER_UNSAFE_RAW);
|
||||
|
||||
if ($output === false) {
|
||||
return "";
|
||||
}
|
||||
$output = strip_tags($output);
|
||||
while (strpos($output, " ") !== false) {
|
||||
$output = str_replace(" ", " ", $output);
|
||||
}
|
||||
@ -97,9 +96,7 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function sanitize_rgb_color(mixed $input):string {
|
||||
|
||||
$output = \filter_var($input,
|
||||
FILTER_SANITIZE_STRING,
|
||||
FILTER_FLAG_NO_ENCODE_QUOTES);
|
||||
$output = \filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
|
||||
|
||||
if ($output === false
|
||||
|| (preg_match('/^[a-zA-Z0-9]{3}$/', $output) === false && preg_match('/^[a-zA-Z0-9]{6}$/', $output) === false)
|
||||
@ -205,6 +202,11 @@ final class MD_STD_IN {
|
||||
throw new MDInvalidUrl("Invalid input URL");
|
||||
}
|
||||
|
||||
// Check for valid schemes
|
||||
if (MD_STD::startsWithAny($input, ['https://', 'http://', 'ftp://']) === false) {
|
||||
throw new MDInvalidUrl("Invalid input URL");
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
@ -231,6 +233,30 @@ final class MD_STD_IN {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a password (minimum requirements: 8 characters, including
|
||||
* one number and one special char) and returns a list of errors,
|
||||
* if there are any.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function validate_password(string $input):array {
|
||||
|
||||
$errors = [];
|
||||
if (mb_strlen($input) < 8) {
|
||||
$errors[] = 'password_too_short';
|
||||
}
|
||||
|
||||
if (!(\preg_match('@[0-9]@', $input)) && !(\preg_match('@[^\w]@', $input))) {
|
||||
$errors[] = 'password_has_no_number_no_special_char';
|
||||
}
|
||||
|
||||
return $errors;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes and validates a phone number. An empty string passes.
|
||||
*
|
||||
@ -295,7 +321,7 @@ final class MD_STD_IN {
|
||||
}
|
||||
|
||||
// ISBN 13
|
||||
if (\mb_strlen($input) === 10) {
|
||||
if (\mb_strlen($input) === 13) {
|
||||
|
||||
if (\preg_match('/\d{13}/i', $input)) {
|
||||
return $input;
|
||||
|
@ -134,14 +134,14 @@ final class MD_STD_SEC {
|
||||
/**
|
||||
* Send CSP headers.
|
||||
*
|
||||
* @param array{default-src: string, connect-src: string, script-src: string, img-src: string, media-src: string, style-src: string, frame-src: string, object-src: string, base-uri: string, form-action: string, frame-ancestors?: string} $directives Directives to send. Font source is always set to 'self', and hence excluded.
|
||||
* @param string $frame_ancestors Frame ancestors directive. Default is to not set it.
|
||||
* @param array{default-src: string, connect-src: string, script-src: string, img-src: string, media-src: string, style-src: string, frame-src: string, object-src: string, base-uri: string, form-action: string, worker-src?: string, frame-ancestors?: string} $directives Directives to send. Font source is always set to 'self', and hence excluded.
|
||||
* @param string $frame_ancestors Frame ancestors directive. Default is to not set it.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function sendContentSecurityPolicy(array $directives, string $frame_ancestors = ""):void {
|
||||
|
||||
$policy = 'Content-Security-Policy: default-src ' . $directives['default-src'] . '; connect-src ' . $directives['connect-src'] . '; script-src ' . $directives['script-src'] . '; img-src ' . $directives['img-src'] . '; media-src ' . $directives['media-src'] . '; style-src ' . $directives['style-src'] . '; font-src \'self\'; frame-src ' . $directives['frame-src'] . '; object-src ' . $directives['object-src'] . '; base-uri ' . $directives['base-uri'] . '; form-action ' . $directives['form-action'] . '; manifest-src \'self\'; worker-src \'self\';';
|
||||
$policy = 'Content-Security-Policy: default-src ' . $directives['default-src'] . '; connect-src ' . $directives['connect-src'] . '; script-src ' . $directives['script-src'] . '; img-src ' . $directives['img-src'] . '; media-src ' . $directives['media-src'] . '; style-src ' . $directives['style-src'] . '; font-src \'self\'; frame-src ' . $directives['frame-src'] . '; object-src ' . $directives['object-src'] . '; base-uri ' . $directives['base-uri'] . '; form-action ' . $directives['form-action'] . '; manifest-src \'self\'; worker-src ' . ($directives['worker-src'] ?? '\'self\'') . ';';
|
||||
|
||||
if (!empty($frame_ancestors)) {
|
||||
$policy .= ' frame-ancestors ' . $frame_ancestors . ';';
|
||||
|
Reference in New Issue
Block a user