Compare commits
34 Commits
06bbaf5f97
...
aa7a3c5012
Author | SHA1 | Date | |
---|---|---|---|
aa7a3c5012
|
|||
3f37dd7a9e
|
|||
86c8235dae
|
|||
8f5174e90d
|
|||
80af1ef260
|
|||
eb869071b8
|
|||
e19e0c875c
|
|||
245d161805
|
|||
a1e6d7773b
|
|||
d35e3ed003
|
|||
9113cad57e
|
|||
143a4680e2
|
|||
a6ebab3e03
|
|||
80ab3216d5
|
|||
2071b57053
|
|||
5e7313f166
|
|||
1c5d451619
|
|||
7fb5ad8ced
|
|||
01ac23229b
|
|||
d53303e617
|
|||
6adf0ee0a2
|
|||
dbbdf4f230
|
|||
f030adba20
|
|||
980c408631
|
|||
a06a6ed41d
|
|||
20c33437c9
|
|||
63d6154d40
|
|||
d03befe483
|
|||
fe0a8ba83b
|
|||
3b5f20aa96
|
|||
56f4fdc88a
|
|||
919ffdb1b5
|
|||
36bdb36986
|
|||
2c1f6a0490
|
19
exceptions/MDJsonEncodingFailedException.php
Normal file
19
exceptions/MDJsonEncodingFailedException.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?PHP
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports a failure to encode JSON data.
|
||||||
|
*/
|
||||||
|
final class MDJsonEncodingFailedException extends Exception {
|
||||||
|
/**
|
||||||
|
* Error message.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function errorMessage() {
|
||||||
|
//error message
|
||||||
|
$errorMsg = 'Failed to encode JSON data.';
|
||||||
|
return $errorMsg;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ final class MD_STD {
|
|||||||
* Wrapper around file_get_contents, that provides catches errors on it and returns
|
* Wrapper around file_get_contents, that provides catches errors on it and returns
|
||||||
* with type safety.
|
* with type safety.
|
||||||
*
|
*
|
||||||
* @param string $filename Filepath of the file to read.
|
* @param non-empty-string $filename Filepath of the file to read.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -37,14 +37,14 @@ final class MD_STD {
|
|||||||
* Returns the real path of a relative file path. Throws an error rather than
|
* Returns the real path of a relative file path. Throws an error rather than
|
||||||
* returning the default false.
|
* returning the default false.
|
||||||
*
|
*
|
||||||
* @param string $path File path to convert.
|
* @param non-empty-string $path File path to convert.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return non-empty-string
|
||||||
*/
|
*/
|
||||||
public static function realpath(string $path):string {
|
public static function realpath(string $path):string {
|
||||||
|
|
||||||
$output = \realpath($path);
|
$output = \realpath($path);
|
||||||
if (!\is_string($output)) {
|
if (!\is_string($output) || empty($output)) {
|
||||||
throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
|
throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
|
||||||
}
|
}
|
||||||
return $output;
|
return $output;
|
||||||
@ -57,7 +57,7 @@ final class MD_STD {
|
|||||||
*
|
*
|
||||||
* @see https://www.php.net/manual/en/function.mkdir.php
|
* @see https://www.php.net/manual/en/function.mkdir.php
|
||||||
*
|
*
|
||||||
* @param string $pathname The directory path.
|
* @param non-empty-string $pathname The directory path.
|
||||||
* @param integer $mode Permissions.
|
* @param integer $mode Permissions.
|
||||||
* @param boolean $recursive Allows the creation of nested directories
|
* @param boolean $recursive Allows the creation of nested directories
|
||||||
* specified in the pathname.
|
* specified in the pathname.
|
||||||
@ -82,7 +82,7 @@ final class MD_STD {
|
|||||||
*
|
*
|
||||||
* @see https://www.php.net/manual/en/function.unlink.php
|
* @see https://www.php.net/manual/en/function.unlink.php
|
||||||
*
|
*
|
||||||
* @param string $filename File path.
|
* @param non-empty-string $filename File path.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -97,9 +97,9 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Gets contents of a folder.
|
* Gets contents of a folder.
|
||||||
*
|
*
|
||||||
* @param string $filepath Directory path.
|
* @param non-empty-string $filepath Directory path.
|
||||||
*
|
*
|
||||||
* @return array<string>
|
* @return array<non-empty-string>
|
||||||
*/
|
*/
|
||||||
public static function scandir(string $filepath):array {
|
public static function scandir(string $filepath):array {
|
||||||
|
|
||||||
@ -135,9 +135,10 @@ final class MD_STD {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function checking if a string starts with another.
|
* Function checking if a string starts with another.
|
||||||
|
* DEPRECATED. Can be replaced by PHP8's str_starts_with.
|
||||||
*
|
*
|
||||||
* @param string $haystack String to check.
|
* @param non-empty-string $haystack String to check.
|
||||||
* @param string $needle Potential start of $haystack.
|
* @param non-empty-string $needle Potential start of $haystack.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
@ -155,7 +156,7 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Function checking if a string starts with any input from the input array.
|
* Function checking if a string starts with any input from the input array.
|
||||||
*
|
*
|
||||||
* @param string $haystack String to check.
|
* @param non-empty-string $haystack String to check.
|
||||||
* @param string[] $needles Array containing potential start values of $haystack.
|
* @param string[] $needles Array containing potential start values of $haystack.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
@ -164,7 +165,7 @@ final class MD_STD {
|
|||||||
|
|
||||||
$output = false;
|
$output = false;
|
||||||
foreach ($needles as $needle) {
|
foreach ($needles as $needle) {
|
||||||
$output = self::startsWith($haystack, $needle);
|
$output = \str_starts_with($haystack, $needle);
|
||||||
if ($output == true) {
|
if ($output == true) {
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
@ -173,12 +174,45 @@ final class MD_STD {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function checking if a string contains another in a case-insensitive way.
|
||||||
|
*
|
||||||
|
* @param non-empty-string $haystack String to check.
|
||||||
|
* @param non-empty-string $needle Potential start of $haystack.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function stri_contains(string $haystack, string $needle):bool {
|
||||||
|
|
||||||
|
if (stripos($haystack, $needle) === false) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function checking if a string contains any of a given set of strings in a
|
||||||
|
* case-insensitive way.
|
||||||
|
*
|
||||||
|
* @param non-empty-string $haystack String to check.
|
||||||
|
* @param array<non-empty-string> $needles Potential values contained in haystack.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function stri_contains_any(string $haystack, array $needles):bool {
|
||||||
|
|
||||||
|
foreach ($needles as $needle) {
|
||||||
|
if (self::stri_contains($haystack, $needle) === true) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-safe(r) wrapper around preg_replace.
|
* Type-safe(r) wrapper around preg_replace.
|
||||||
*
|
*
|
||||||
* @param string $pattern The pattern to search for. It can be either a string or an array with strings.
|
* @param non-empty-string $pattern The pattern to search for. It can be either a string or an array with strings.
|
||||||
* @param string $replacement To replace with.
|
* @param string $replacement To replace with.
|
||||||
* @param string $subject The string or an array with strings to search and replace.
|
* @param non-empty-string $subject The string or an array with strings to search and replace.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -208,7 +242,28 @@ final class MD_STD {
|
|||||||
|
|
||||||
$output = \json_encode($value, $options, $depth);
|
$output = \json_encode($value, $options, $depth);
|
||||||
if ($output === false) {
|
if ($output === false) {
|
||||||
throw new Exception("JSON output could not be generated");
|
throw new MDJsonEncodingFailedException("JSON output could not be generated");
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-safe wrapper around json_encode for objects.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function json_encode_object(object $value, int $options = 0, int $depth = 512):string {
|
||||||
|
|
||||||
|
$output = \json_encode($value, $options, $depth);
|
||||||
|
if ($output === false) {
|
||||||
|
throw new MDJsonEncodingFailedException("JSON output could not be generated");
|
||||||
}
|
}
|
||||||
return $output;
|
return $output;
|
||||||
|
|
||||||
@ -234,10 +289,10 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Initializes a curl request with the given presets.
|
* Initializes a curl request with the given presets.
|
||||||
*
|
*
|
||||||
* @param string $url URL to query.
|
* @param non-empty-string $url URL to query.
|
||||||
* @param integer $timeout Timeout in milliseconds.
|
* @param integer $timeout Timeout in milliseconds.
|
||||||
*
|
*
|
||||||
* @return resource
|
* @return CurlHandle
|
||||||
*/
|
*/
|
||||||
public static function curl_init(string $url, int $timeout) {
|
public static function curl_init(string $url, int $timeout) {
|
||||||
|
|
||||||
@ -266,15 +321,20 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Wrapper for curling contents from the web.
|
* Wrapper for curling contents from the web.
|
||||||
*
|
*
|
||||||
* @param string $url URL to query.
|
* @param non-empty-string $url URL to query.
|
||||||
* @param integer $timeout Timeout in milliseconds.
|
* @param integer $timeout Timeout in milliseconds.
|
||||||
|
* @param array<string> $headers HTTP headers to pass on.
|
||||||
|
* Analogous to CURLOPT_HTTPHEADER.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function runCurl(string $url, int $timeout = 1200):string {
|
public static function runCurl(string $url, int $timeout = 1200, array $headers = []):string {
|
||||||
|
|
||||||
$curl = self::curl_init($url, $timeout);
|
$curl = self::curl_init($url, $timeout);
|
||||||
\curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
\curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
if (!empty($headers)) {
|
||||||
|
\curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
$result = \curl_exec($curl);
|
$result = \curl_exec($curl);
|
||||||
|
|
||||||
@ -293,53 +353,96 @@ final class MD_STD {
|
|||||||
* Wrapper for curling multiple pages from the web at ones and returning their contents.
|
* Wrapper for curling multiple pages from the web at ones and returning their contents.
|
||||||
* Adapted from hushuilong's comment at https://www.php.net/manual/de/function.curl-multi-init.php#105252.
|
* Adapted from hushuilong's comment at https://www.php.net/manual/de/function.curl-multi-init.php#105252.
|
||||||
*
|
*
|
||||||
* @param array<string> $urls URL to query.
|
* @param non-empty-array<non-empty-string> $urls URL to query.
|
||||||
* @param integer $timeout Timeout in milliseconds.
|
* @param integer $timeout Timeout in milliseconds.
|
||||||
|
* @param array<string> $headers HTTP headers to pass on.
|
||||||
|
* Analogous to CURLOPT_HTTPHEADER.
|
||||||
*
|
*
|
||||||
* @return array<string>
|
* @return array<string>
|
||||||
*/
|
*/
|
||||||
public static function runCurlMulti(array $urls, int $timeout = 1200):array {
|
public static function runCurlMulti(array $urls, int $timeout = 1200, array $headers = []):array {
|
||||||
|
|
||||||
if (!($mh = curl_multi_init())) {
|
$mh = \curl_multi_init();
|
||||||
throw new exception("Failed to set up multi handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
$curl_array = [];
|
$curl_array = [];
|
||||||
foreach($urls as $i => $url) {
|
foreach($urls as $i => $url) {
|
||||||
|
|
||||||
$curl_array[$i] = self::curl_init($url, $timeout);
|
$curl_array[$i] = self::curl_init($url, $timeout);
|
||||||
|
|
||||||
curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
|
\curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_multi_add_handle($mh, $curl_array[$i]);
|
if (!empty($headers)) {
|
||||||
|
\curl_setopt($curl_array[$i], CURLOPT_HTTPHEADER, $headers);
|
||||||
|
}
|
||||||
|
\curl_multi_add_handle($mh, $curl_array[$i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$running = null;
|
$running = null;
|
||||||
do {
|
do {
|
||||||
usleep(10000);
|
\usleep(10000);
|
||||||
curl_multi_exec($mh, $running);
|
\curl_multi_exec($mh, $running);
|
||||||
} while($running > 0);
|
} while($running > 0);
|
||||||
|
|
||||||
$res = [];
|
$res = [];
|
||||||
foreach($urls as $i => $url) {
|
foreach($urls as $i => $url) {
|
||||||
$res[$i] = curl_multi_getcontent($curl_array[$i]);
|
$res[$i] = \curl_multi_getcontent($curl_array[$i]) ?: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($urls as $i => $url){
|
foreach($urls as $i => $url){
|
||||||
curl_multi_remove_handle($mh, $curl_array[$i]);
|
\curl_multi_remove_handle($mh, $curl_array[$i]);
|
||||||
}
|
}
|
||||||
curl_multi_close($mh);
|
\curl_multi_close($mh);
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets and returns user language based on a session cookie.
|
||||||
|
*
|
||||||
|
* @param non-empty-array<non-empty-string> $allowed_langs Allowed languages.
|
||||||
|
* @param non-empty-string $default_lang Default language.
|
||||||
|
*
|
||||||
|
* @return non-empty-string
|
||||||
|
*/
|
||||||
|
public static function get_user_lang(array $allowed_langs, string $default_lang):string {
|
||||||
|
|
||||||
|
$cookie_options = [
|
||||||
|
'expires' => self::strtotime("+1 month"),
|
||||||
|
'path' => '/',
|
||||||
|
'secure' => true,
|
||||||
|
'httponly' => true,
|
||||||
|
'samesite' => 'Lax' // None || Lax || Strict
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($_GET['navlang']) and in_array($_GET['navlang'], $allowed_langs, true)) {
|
||||||
|
if (!setcookie('__Host-lang', $_GET['navlang'], $cookie_options)) {
|
||||||
|
throw new Exception("Failed to set language");
|
||||||
|
}
|
||||||
|
$lang = $_GET['navlang'];
|
||||||
|
}
|
||||||
|
else if (isset($_COOKIE['__Host-lang']) and in_array($_COOKIE['__Host-lang'], $allowed_langs, true)) {
|
||||||
|
$lang = $_COOKIE['__Host-lang'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$lang = self::lang_getfrombrowser($allowed_langs, $default_lang, "", false);
|
||||||
|
if (!setcookie('__Host-lang', $lang, $cookie_options)) {
|
||||||
|
throw new Exception("Failed to set language");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($lang)) return $default_lang;
|
||||||
|
|
||||||
|
return $lang;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function lang_getfrombrowser gets the browser language based on HTTP headers.
|
* Function lang_getfrombrowser gets the browser language based on HTTP headers.
|
||||||
*
|
*
|
||||||
* @param array<string> $allowed_languages Array containing all the languages for which
|
* @param non-empty-array<non-empty-string> $allowed_languages Array containing all the languages for which
|
||||||
* there are translations.
|
* there are translations.
|
||||||
* @param string $default_language Default language of the instance of MD.
|
* @param non-empty-string $default_language Default language of the instance of MD.
|
||||||
* @param string $lang_variable Currently set language variable. Optional.
|
* @param string $lang_variable Currently set language variable. Optional.
|
||||||
* @param boolean $strict_mode Whether to demand "de-de" (true) or "de" (false) Optional.
|
* @param boolean $strict_mode Whether to demand "de-de" (true) or "de" (false) Optional.
|
||||||
*
|
*
|
||||||
@ -374,9 +477,7 @@ final class MD_STD {
|
|||||||
foreach ($accepted_languages as $accepted_language) {
|
foreach ($accepted_languages as $accepted_language) {
|
||||||
|
|
||||||
// Alle Infos über diese Sprache rausholen
|
// Alle Infos über diese Sprache rausholen
|
||||||
// phpcs:disable Generic.Strings.UnnecessaryStringConcat
|
|
||||||
$res = \preg_match('/^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i', $accepted_language, $matches);
|
$res = \preg_match('/^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i', $accepted_language, $matches);
|
||||||
// phpcs:enable
|
|
||||||
|
|
||||||
// war die Syntax gültig?
|
// war die Syntax gültig?
|
||||||
if (!$res) {
|
if (!$res) {
|
||||||
@ -398,9 +499,7 @@ final class MD_STD {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bis der Sprachcode leer ist...
|
// Bis der Sprachcode leer ist...
|
||||||
// phpcs:disable Squiz.PHP.DisallowSizeFunctionsInLoops
|
|
||||||
while (!empty($lang_code)) {
|
while (!empty($lang_code)) {
|
||||||
// phpcs:enable
|
|
||||||
// mal sehen, ob der Sprachcode angeboten wird
|
// mal sehen, ob der Sprachcode angeboten wird
|
||||||
if (\in_array(\strtolower(\join('-', $lang_code)), $allowed_languages, true)) {
|
if (\in_array(\strtolower(\join('-', $lang_code)), $allowed_languages, true)) {
|
||||||
// Qualität anschauen
|
// Qualität anschauen
|
||||||
@ -430,7 +529,7 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Type-safe wrapper around filesize, if output is false, throws an error.
|
* Type-safe wrapper around filesize, if output is false, throws an error.
|
||||||
*
|
*
|
||||||
* @param string $filename File name.
|
* @param non-empty-string $filename File name.
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
@ -453,11 +552,11 @@ final class MD_STD {
|
|||||||
* @param integer $bytes A file size, e.g. returned from filesize().
|
* @param integer $bytes A file size, e.g. returned from filesize().
|
||||||
* @param integer $decimals Number of decimal digits to allow.
|
* @param integer $decimals Number of decimal digits to allow.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return non-empty-string
|
||||||
*/
|
*/
|
||||||
public static function human_filesize(int $bytes, int $decimals = 2):string {
|
public static function human_filesize(int $bytes, int $decimals = 2):string {
|
||||||
|
|
||||||
$size = ['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
|
$size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
$factor = \floor((\strlen((string)$bytes) - 1) / 3);
|
$factor = \floor((\strlen((string)$bytes) - 1) / 3);
|
||||||
return \sprintf("%.{$decimals}f", $bytes / \pow(1024, $factor)) . $size[$factor];
|
return \sprintf("%.{$decimals}f", $bytes / \pow(1024, $factor)) . $size[$factor];
|
||||||
|
|
||||||
@ -473,9 +572,6 @@ final class MD_STD {
|
|||||||
public static function openssl_random_pseudo_bytes(int $length):string {
|
public static function openssl_random_pseudo_bytes(int $length):string {
|
||||||
|
|
||||||
$output = \openssl_random_pseudo_bytes($length);
|
$output = \openssl_random_pseudo_bytes($length);
|
||||||
if ($output === false) {
|
|
||||||
throw new Exception("Failed generating random pseudo bytes using openssl_random_pseudo_bytes");
|
|
||||||
}
|
|
||||||
return $output;
|
return $output;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -523,7 +619,7 @@ final class MD_STD {
|
|||||||
/**
|
/**
|
||||||
* Wrapper around the finfo functions to get the mime content type of a file.
|
* Wrapper around the finfo functions to get the mime content type of a file.
|
||||||
*
|
*
|
||||||
* @param string $filepath Expected file path.
|
* @param non-empty-string $filepath Expected file path.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -541,10 +637,40 @@ final class MD_STD {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around the finfo functions to get the mime content type of a file.
|
||||||
|
*
|
||||||
|
* @param non-empty-string $url Expected file path.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function remote_mime_content_type(string $url):string {
|
||||||
|
|
||||||
|
if (empty($tmp_file = \tempnam(\sys_get_temp_dir(), "remote_mime_type_check"))) {
|
||||||
|
throw new Exception("Failed to get temporary file location");
|
||||||
|
}
|
||||||
|
|
||||||
|
$fp = \fopen($tmp_file, 'w');
|
||||||
|
|
||||||
|
if (!($ch = \curl_init($url))) {
|
||||||
|
throw new Exception("Failed to initialize curl for $url");
|
||||||
|
};
|
||||||
|
|
||||||
|
\curl_setopt($ch, CURLOPT_FILE, $fp);
|
||||||
|
\curl_exec($ch);
|
||||||
|
\curl_close($ch);
|
||||||
|
|
||||||
|
$mime_type = MD_STD::mime_content_type($tmp_file);
|
||||||
|
self::unlink($tmp_file);
|
||||||
|
|
||||||
|
return $mime_type;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a file exists, with one of the expected mime types.
|
* Checks if a file exists, with one of the expected mime types.
|
||||||
*
|
*
|
||||||
* @param string $filepath File path of the file that needs to exist.
|
* @param non-empty-string $filepath File path of the file that needs to exist.
|
||||||
* @param string[] $accepted_mimetype Mime type the file should have.
|
* @param string[] $accepted_mimetype Mime type the file should have.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
@ -572,7 +698,7 @@ final class MD_STD {
|
|||||||
* Wrapper around exec, to be used with editing functions.
|
* Wrapper around exec, to be used with editing functions.
|
||||||
* Pipes STDERR to STDOUT and throws an Exception on any error.
|
* Pipes STDERR to STDOUT and throws an Exception on any error.
|
||||||
*
|
*
|
||||||
* @param string $cmds Commands to run.
|
* @param non-empty-string $cmds Commands to run.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -616,8 +742,56 @@ final class MD_STD {
|
|||||||
*/
|
*/
|
||||||
public static function string_to_color_code(string $str):string {
|
public static function string_to_color_code(string $str):string {
|
||||||
|
|
||||||
$code = substr(dechex(crc32($str)), 0, 6);
|
$code = \substr(\dechex(\crc32($str)), 0, 6);
|
||||||
return $code;
|
return $code;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a directory is writable.
|
||||||
|
*
|
||||||
|
* @param non-empty-string $dir Directory path.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function check_is_writable(string $dir):void {
|
||||||
|
|
||||||
|
if (\is_dir($dir) === false) {
|
||||||
|
throw new MDFileDoesNotExist("Directory " . $dir . " does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_writable($dir) === false) {
|
||||||
|
throw new MDFileIsNotWritable("Directory " . $dir . " is not writable");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits an lists of integers into parts of a predefined size and returns those
|
||||||
|
* as sub-lists of a superordinate list.
|
||||||
|
*
|
||||||
|
* @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>>
|
||||||
|
*/
|
||||||
|
public static function split_int_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -16,6 +16,20 @@ final class MD_STD_CACHE {
|
|||||||
/** @var integer */
|
/** @var integer */
|
||||||
public static int $redis_port = 6379;
|
public static int $redis_port = 6379;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a connection to redis.
|
||||||
|
*
|
||||||
|
* @return Redis
|
||||||
|
*/
|
||||||
|
public static function open_redis_default():Redis {
|
||||||
|
|
||||||
|
$redis = new Redis();
|
||||||
|
$redis->connect(self::$redis_host, self::$redis_port, 1, null, 0, 0, ['auth' => [MD_CONF::$redis_pw]]);
|
||||||
|
|
||||||
|
return $redis;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shutdown function for caching contents of output buffer.
|
* Shutdown function for caching contents of output buffer.
|
||||||
*
|
*
|
||||||
@ -29,8 +43,8 @@ final class MD_STD_CACHE {
|
|||||||
$outputT = trim(MD_STD::minimizeHTMLString(MD_STD::ob_get_clean()));
|
$outputT = trim(MD_STD::minimizeHTMLString(MD_STD::ob_get_clean()));
|
||||||
echo $outputT;
|
echo $outputT;
|
||||||
|
|
||||||
$redis = new Redis();
|
$redis = self::open_redis_default();
|
||||||
$redis->connect(self::$redis_host, self::$redis_port, 1, null, 0, 0, ['auth' => [MD_CONF::$redis_pw]]);
|
|
||||||
$redis->set($redisKey, $outputT);
|
$redis->set($redisKey, $outputT);
|
||||||
$redis->expire($redisKey, $expiry);
|
$redis->expire($redisKey, $expiry);
|
||||||
$redis->close();
|
$redis->close();
|
||||||
@ -52,8 +66,8 @@ final class MD_STD_CACHE {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$redis = new Redis();
|
$redis = self::open_redis_default();
|
||||||
$redis->connect(self::$redis_host, self::$redis_port, 1, null, 0, 0, ['auth' => [MD_CONF::$redis_pw]]);
|
|
||||||
if ($redis->ping() !== false) {
|
if ($redis->ping() !== false) {
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
35
src/MD_STD_DEBUG.php
Normal file
35
src/MD_STD_DEBUG.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Provides basic debugging functions.
|
||||||
|
*/
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard class providing simple and generally applicable
|
||||||
|
* debugging and code improvement functions.
|
||||||
|
*/
|
||||||
|
final class MD_STD_DEBUG {
|
||||||
|
/**
|
||||||
|
* Function simpleBenchmark prints the difference between start time and the time at the exit of script
|
||||||
|
* Should be put very early in the script.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function simpleBenchmark():void {
|
||||||
|
|
||||||
|
$start = \microtime(true);
|
||||||
|
\register_shutdown_function(function($start) :void {
|
||||||
|
echo PHP_EOL . '<pre>';
|
||||||
|
echo \microtime(true) - $start . "<br/>";
|
||||||
|
echo 'RAM Usage (Peak): ' . \memory_get_peak_usage() . "<br/>";
|
||||||
|
echo 'RAM Usage: ' . \memory_get_usage() . "<br/>";
|
||||||
|
if ($loadAvg = \sys_getloadavg()) {
|
||||||
|
echo 'Load avg. (last 1 minute): ' . $loadAvg[0] . '<br />';
|
||||||
|
echo 'Load avg. (last 5 minute): ' . $loadAvg[1] . '<br />';
|
||||||
|
echo 'Load avg. (last 15 minute): ' . $loadAvg[2] . '<br />';
|
||||||
|
}
|
||||||
|
echo '</pre>';
|
||||||
|
}, $start);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,7 @@
|
|||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard class providing overrides of default PHP functions as static
|
* Encapsulates functions for handling inputs.
|
||||||
* functions.
|
|
||||||
*/
|
*/
|
||||||
final class MD_STD_IN {
|
final class MD_STD_IN {
|
||||||
/**
|
/**
|
||||||
@ -17,7 +16,7 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public static function sanitize_id($input):int {
|
public static function sanitize_id(mixed $input):int {
|
||||||
|
|
||||||
$input = \filter_var($input, \FILTER_VALIDATE_INT, [
|
$input = \filter_var($input, \FILTER_VALIDATE_INT, [
|
||||||
'options' => [
|
'options' => [
|
||||||
@ -27,7 +26,7 @@ final class MD_STD_IN {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!($input)) {
|
if (!$input) {
|
||||||
throw new MDpageParameterNotNumericException("Value is not numeric.");
|
throw new MDpageParameterNotNumericException("Value is not numeric.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public static function sanitize_id_or_zero($input):int {
|
public static function sanitize_id_or_zero(mixed $input):int {
|
||||||
|
|
||||||
if ($input === "") {
|
if ($input === "") {
|
||||||
return 0;
|
return 0;
|
||||||
@ -72,7 +71,7 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function sanitize_text($input):string {
|
public static function sanitize_text(mixed $input):string {
|
||||||
|
|
||||||
$output = \filter_var($input,
|
$output = \filter_var($input,
|
||||||
FILTER_SANITIZE_STRING,
|
FILTER_SANITIZE_STRING,
|
||||||
@ -96,14 +95,14 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function sanitize_rgb_color($input):string {
|
public static function sanitize_rgb_color(mixed $input):string {
|
||||||
|
|
||||||
$output = \filter_var($input,
|
$output = \filter_var($input,
|
||||||
FILTER_SANITIZE_STRING,
|
FILTER_SANITIZE_STRING,
|
||||||
FILTER_FLAG_NO_ENCODE_QUOTES);
|
FILTER_FLAG_NO_ENCODE_QUOTES);
|
||||||
|
|
||||||
if ($output === false
|
if ($output === false
|
||||||
|| ((preg_match('/^[a-zA-Z0-9]{3}$/', $output)) === false && (preg_match('/^[a-zA-Z0-9]{6}$/', $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);
|
throw new MDInvalidColorCode("Invalid color code provided: " . $output);
|
||||||
}
|
}
|
||||||
@ -112,11 +111,30 @@ final class MD_STD_IN {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valiates a list of entries, ensuring all returned values are valid IDs.
|
||||||
|
*
|
||||||
|
* @param array<mixed> $inputs Input array.
|
||||||
|
*
|
||||||
|
* @return array<integer>
|
||||||
|
*/
|
||||||
|
public static function sanitize_id_array(array $inputs):array {
|
||||||
|
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach ($inputs as $input) {
|
||||||
|
$output[] = self::sanitize_id($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves HTTP input texts from GET or POST variables, whatever is provided.
|
* Retrieves HTTP input texts from GET or POST variables, whatever is provided.
|
||||||
* If neither is given, returns a provided default.
|
* If neither is given, returns a provided default.
|
||||||
*
|
*
|
||||||
* @param string $var_name Variable name.
|
* @param non-empty-string $var_name Variable name.
|
||||||
* @param string $default Default value for the output.
|
* @param string $default Default value for the output.
|
||||||
* @param array<string> $allowed List of allowed values. Defaults to empty (all values allowed).
|
* @param array<string> $allowed List of allowed values. Defaults to empty (all values allowed).
|
||||||
*
|
*
|
||||||
@ -146,7 +164,7 @@ final class MD_STD_IN {
|
|||||||
* Retrieves HTTP input texts from POST variables.
|
* Retrieves HTTP input texts from POST variables.
|
||||||
* If none is given, returns a provided default.
|
* If none is given, returns a provided default.
|
||||||
*
|
*
|
||||||
* @param string $var_name Variable name.
|
* @param non-empty-string $var_name Variable name.
|
||||||
* @param string $default Default value for the output.
|
* @param string $default Default value for the output.
|
||||||
* @param array<string> $allowed List of allowed values. Defaults to empty (all values allowed).
|
* @param array<string> $allowed List of allowed values. Defaults to empty (all values allowed).
|
||||||
*
|
*
|
||||||
@ -176,7 +194,7 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function sanitize_url($input):string {
|
public static function sanitize_url(mixed $input):string {
|
||||||
|
|
||||||
if ($input === "") {
|
if ($input === "") {
|
||||||
return "";
|
return "";
|
||||||
@ -198,7 +216,7 @@ final class MD_STD_IN {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function sanitize_email($input):string {
|
public static function sanitize_email(mixed $input):string {
|
||||||
|
|
||||||
if ($input === "") {
|
if ($input === "") {
|
||||||
return "";
|
return "";
|
||||||
@ -213,6 +231,27 @@ final class MD_STD_IN {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes and validates a phone number. An empty string passes.
|
||||||
|
*
|
||||||
|
* @param mixed $input Input string.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function validate_phone_number(mixed $input):string {
|
||||||
|
|
||||||
|
if ($input === "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match("#^[()0-9/ +-]+$#", $input)) {
|
||||||
|
throw new MDgenericInvalidInputsException("Invalid phone number entered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $input;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes a string to a float.
|
* Sanitizes a string to a float.
|
||||||
*
|
*
|
||||||
@ -267,4 +306,84 @@ final class MD_STD_IN {
|
|||||||
throw new MDgenericInvalidInputsException("ISBNs must be either 10 or 13 characters long.");
|
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 non-empty-string $filename Name of the file to upload.
|
||||||
|
* @param non-empty-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);
|
||||||
|
if (empty($destDir = dirname($destination))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MD_STD::check_is_writable($destDir);
|
||||||
|
|
||||||
|
if (!(\move_uploaded_file($filename, $destination))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,9 +5,19 @@
|
|||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class providing static functions with basic security operations.
|
* Gathers wrappers for handling basic security operations.
|
||||||
*/
|
*/
|
||||||
final class MD_STD_SEC {
|
final class MD_STD_SEC {
|
||||||
|
|
||||||
|
const REFRESH_TIME_GENERAL = 60; // Time until the comp. with the whole service is cleared.
|
||||||
|
const REFRESH_TIME_USER = 600; // Time until the comp. with the same username service is cleared.
|
||||||
|
const REFRESH_TIME_IP = 180; // Time until the comp. with the same IP is cleared. This should be lower than the user-level one, as people working together may be using a common IP.
|
||||||
|
|
||||||
|
const BRUTE_FORCE_DELAY_DEFAULT = 2000; // 2000 microseconds = 2 milliseconds
|
||||||
|
const BRUTE_FORCE_DELAY_MULTIPLIER_COMMON = 1.08;
|
||||||
|
const BRUTE_FORCE_DELAY_MULTIPLIER_PER_USER = 2.8;
|
||||||
|
const BRUTE_FORCE_DELAY_MULTIPLIER_PER_IP = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for retrieving the anti-csrf token or generating it if need be.
|
* Function for retrieving the anti-csrf token or generating it if need be.
|
||||||
*
|
*
|
||||||
@ -45,11 +55,6 @@ final class MD_STD_SEC {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BRUTE_FORCE_DELAY_DEFAULT = 2000; // 2000 microseconds = 2 milliseconds
|
|
||||||
const BRUTE_FORCE_DELAY_MULTIPLIER_COMMON = 1.08;
|
|
||||||
const BRUTE_FORCE_DELAY_MULTIPLIER_PER_USER = 1.8;
|
|
||||||
const BRUTE_FORCE_DELAY_MULTIPLIER_PER_IP = 4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent brute force attacks by delaying the login .
|
* Prevent brute force attacks by delaying the login .
|
||||||
*
|
*
|
||||||
@ -62,7 +67,7 @@ final class MD_STD_SEC {
|
|||||||
|
|
||||||
// Unstable but working way to get the user's IP. If the IP is falsified,
|
// Unstable but working way to get the user's IP. If the IP is falsified,
|
||||||
// this can't be found out anyway and security is established by _common.
|
// this can't be found out anyway and security is established by _common.
|
||||||
$ip = \strval($_SERVER['REMOTE_ADDR'] ?: ($_SERVER['HTTP_X_FORWARDED_FOR'] ?: $_SERVER['HTTP_CLIENT_IP']));
|
$ip = \filter_var($_SERVER['REMOTE_ADDR'] ?: ($_SERVER['HTTP_X_FORWARDED_FOR'] ?: $_SERVER['HTTP_CLIENT_IP']), \FILTER_VALIDATE_IP) ?: "Failed to find";
|
||||||
|
|
||||||
// Set name of log file
|
// Set name of log file
|
||||||
$logfile_common = \sys_get_temp_dir() . "/logins_{$tool_name}.json";
|
$logfile_common = \sys_get_temp_dir() . "/logins_{$tool_name}.json";
|
||||||
@ -81,26 +86,26 @@ final class MD_STD_SEC {
|
|||||||
$loginLog = \json_decode(MD_STD::file_get_contents($logfile_common), \true) ?: [];
|
$loginLog = \json_decode(MD_STD::file_get_contents($logfile_common), \true) ?: [];
|
||||||
|
|
||||||
// Ensure the counters exist and aren't old than 600 seconds / 10 minutes
|
// Ensure the counters exist and aren't old than 600 seconds / 10 minutes
|
||||||
if (empty($loginLog['common']) || \time() - $loginLog['common']['time'] > 600) {
|
if (empty($loginLog['common']) || \time() - $loginLog['common']['time'] > self::REFRESH_TIME_GENERAL) {
|
||||||
$loginLog['common'] = ["count" => 0, "time" => \time()];
|
$loginLog['common'] = ["count" => 0, "time" => \time()];
|
||||||
}
|
}
|
||||||
if (empty($loginLog['usr'][$hash_user]) || \time() - $loginLog['usr'][$hash_user]['time'] > 600) {
|
if (empty($loginLog['usr'][$hash_user]) || \time() - $loginLog['usr'][$hash_user]['time'] > self::REFRESH_TIME_USER) {
|
||||||
$loginLog['usr'][$hash_user] = ["count" => 0, "time" => \time()];
|
$loginLog['usr'][$hash_user] = ["count" => 0, "time" => \time()];
|
||||||
}
|
}
|
||||||
if (empty($loginLog['ip'][$hash_ip]) || \time() - $loginLog['ip'][$hash_ip]['time'] > 600) {
|
if (empty($loginLog['ip'][$hash_ip]) || \time() - $loginLog['ip'][$hash_ip]['time'] > self::REFRESH_TIME_IP) {
|
||||||
$loginLog['ip'][$hash_ip] = ["count" => 0, "time" => \time()];
|
$loginLog['ip'][$hash_ip] = ["count" => 0, "time" => \time()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase counters and update timers
|
// Increase counters and update timers
|
||||||
$loginLog['common']['count']++;
|
++$loginLog['common']['count'];
|
||||||
$loginLog['common']['time'] = \time();
|
$loginLog['common']['time'] = \time();
|
||||||
$loginLog['usr'][$hash_user]['count']++;
|
++$loginLog['usr'][$hash_user]['count'];
|
||||||
$loginLog['usr'][$hash_user]['time'] = \time();
|
$loginLog['usr'][$hash_user]['time'] = \time();
|
||||||
$loginLog['ip'][$hash_ip]['count']++;
|
++$loginLog['ip'][$hash_ip]['count'];
|
||||||
$loginLog['ip'][$hash_ip]['time'] = \time();
|
$loginLog['ip'][$hash_ip]['time'] = \time();
|
||||||
|
|
||||||
// Update the log file
|
// Update the log file
|
||||||
\file_put_contents($logfile_common, \json_encode($loginLog));
|
\file_put_contents($logfile_common, MD_STD::json_encode($loginLog));
|
||||||
|
|
||||||
// Translate counters into delay multipliers
|
// Translate counters into delay multipliers
|
||||||
$delay_multiplier_common = $loginLog['common']['count'];
|
$delay_multiplier_common = $loginLog['common']['count'];
|
||||||
@ -136,7 +141,7 @@ final class MD_STD_SEC {
|
|||||||
*/
|
*/
|
||||||
public static function sendContentSecurityPolicy(array $directives, string $frame_ancestors = ""):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\';';
|
$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\';';
|
||||||
|
|
||||||
if (!empty($frame_ancestors)) {
|
if (!empty($frame_ancestors)) {
|
||||||
$policy .= ' frame-ancestors ' . $frame_ancestors . ';';
|
$policy .= ' frame-ancestors ' . $frame_ancestors . ';';
|
84
src/MD_STD_SORT.php
Normal file
84
src/MD_STD_SORT.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Provides basic helper functions for sorting.
|
||||||
|
*/
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard class providing basic helper functions for sorting.
|
||||||
|
*/
|
||||||
|
final class MD_STD_SORT {
|
||||||
|
/**
|
||||||
|
* Provides a function usable by usort that sorts first by string occurence,
|
||||||
|
* then by a similarity as provided by an outside array.
|
||||||
|
*
|
||||||
|
* @param string $nameIndex Index of the name column.
|
||||||
|
* @param string $searchValue Value to search for.
|
||||||
|
* @param string $sortIndex Index to sort by in case the name index didn't return a hit.
|
||||||
|
*
|
||||||
|
* @return closure
|
||||||
|
*/
|
||||||
|
public static function sort_by_string_occurence_and_int(string $nameIndex, string $searchValue, string $sortIndex):closure {
|
||||||
|
|
||||||
|
return function (array $a, array $b) use ($nameIndex, $searchValue, $sortIndex) {
|
||||||
|
|
||||||
|
if ($a == $b) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a[$nameIndex] === $searchValue) return -1;
|
||||||
|
if ($b[$nameIndex] === $searchValue) return 1;
|
||||||
|
|
||||||
|
$containsSearchA = stripos($a[$nameIndex], $searchValue);
|
||||||
|
$containsSearchB = stripos($b[$nameIndex], $searchValue);
|
||||||
|
|
||||||
|
if ($containsSearchA !== false and $containsSearchB !== false) {
|
||||||
|
return $a[$sortIndex] > $b[$sortIndex] ? -1 : 1;
|
||||||
|
}
|
||||||
|
if ($containsSearchA !== false) return -1;
|
||||||
|
if ($containsSearchB !== false) return 1;
|
||||||
|
|
||||||
|
return $a[$sortIndex] > $b[$sortIndex] ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a function usable by usort that sorts first by string occurence,
|
||||||
|
* then by an integer value provided in another part of the array.
|
||||||
|
*
|
||||||
|
* @param string $nameIndex Index of the name column.
|
||||||
|
* @param string $searchValue Value to search for.
|
||||||
|
* @param array<integer|float> $extSortBy External list to sort by, e.g.
|
||||||
|
* similarities as per levinsthein.
|
||||||
|
* @param string $sortIndex Index to sort by in case the name
|
||||||
|
* index didn't return a hit.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return closure
|
||||||
|
*/
|
||||||
|
public static function sort_by_string_occurence_and_ext_sort_index(string $nameIndex, string $searchValue, array $extSortBy, string $sortIndex):closure {
|
||||||
|
|
||||||
|
return function (array $a, array $b) use ($nameIndex, $searchValue, $extSortBy, $sortIndex) {
|
||||||
|
|
||||||
|
if ($a == $b) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a[$nameIndex] === $searchValue) return -1;
|
||||||
|
if ($b[$nameIndex] === $searchValue) return 1;
|
||||||
|
|
||||||
|
$containsSearchA = stripos($a[$nameIndex], $searchValue);
|
||||||
|
$containsSearchB = stripos($b[$nameIndex], $searchValue);
|
||||||
|
|
||||||
|
if ($containsSearchA !== false and $containsSearchB !== false) {
|
||||||
|
return $extSortBy[$a[$sortIndex]] > $extSortBy[$b[$sortIndex]] ? -1 : 1;
|
||||||
|
}
|
||||||
|
if ($containsSearchA !== false) return -1;
|
||||||
|
if ($containsSearchB !== false) return 1;
|
||||||
|
|
||||||
|
return $extSortBy[$a[$sortIndex]] > $extSortBy[$b[$sortIndex]] ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user