Compare commits
28 Commits
dc9d7abe14
...
8aa9d94acf
Author | SHA1 | Date | |
---|---|---|---|
8aa9d94acf
|
|||
217e1fc86b
|
|||
605fd88b6e
|
|||
7a252c6bfa
|
|||
89e06769f1
|
|||
9d4d326d6a
|
|||
298e2238a8
|
|||
d28c245a1a
|
|||
2b4abf6338
|
|||
34c2d57e5b
|
|||
287fb02f8c
|
|||
d028ac0176
|
|||
ddab52b1a5
|
|||
ada82f07b6
|
|||
cad5b4a6f8
|
|||
6a7f91ef1d
|
|||
6db2b4cc1f
|
|||
4c5097701f
|
|||
886acead63
|
|||
35c0fe4723
|
|||
a38c3c6fae
|
|||
57da808a6a
|
|||
558ed729dc
|
|||
14c7ffb8d4
|
|||
a16619b78e
|
|||
90997e4eb5
|
|||
c60932088d
|
|||
258781307d
|
11
MD_JAIL.php
11
MD_JAIL.php
@ -5,7 +5,7 @@
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* A class that, once initialized, forces the programmer to make security instructions implicit.
|
||||
* A class that, once initialized, forces the programmer to make security instructions explicit.
|
||||
* If an object of the class has been created, not specifying security instructions
|
||||
* leads to an error.
|
||||
* A restriction on basic file operations is not practical in an md context because of
|
||||
@ -178,7 +178,7 @@ final class MD_JAIL {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _apply_basedir_restriction():void {
|
||||
private function _apply_basedir_restriction():void {
|
||||
|
||||
if (empty($this->_open_basedir)) {
|
||||
throw new MDJailSecurityOptionNotSetException("It has not been specified, which memory limit the script should hold. Set MD_JAIL->open_basedir = string.");
|
||||
@ -187,7 +187,7 @@ final class MD_JAIL {
|
||||
throw new Exception('Failed to set open_basedir restrictions');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces security options previously set.
|
||||
@ -208,6 +208,7 @@ final class MD_JAIL {
|
||||
|
||||
$this->_status = self::STATUS_SPECIFIED;
|
||||
$this->__destruct();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_apply_memory_limit();
|
||||
@ -233,6 +234,9 @@ final class MD_JAIL {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor. Throws an exception if the settings have not been set.
|
||||
*/
|
||||
public function __destruct() {
|
||||
|
||||
if ($this->_status !== self::STATUS_SPECIFIED) {
|
||||
@ -255,6 +259,5 @@ final class MD_JAIL {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
238
MD_STD.php
238
MD_STD.php
@ -44,11 +44,56 @@ final class MD_STD {
|
||||
public static function realpath(string $path):string {
|
||||
|
||||
$output = \realpath($path);
|
||||
if (!\is_string($output)) throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
|
||||
if (!\is_string($output)) {
|
||||
throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around mkdir, that throws an exception, if the folder cannot be
|
||||
* created.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.mkdir.php
|
||||
*
|
||||
* @param string $pathname The directory path.
|
||||
* @param integer $mode Permissions.
|
||||
* @param boolean $recursive Allows the creation of nested directories
|
||||
* specified in the pathname.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function mkdir(string $pathname, int $mode = 0775, bool $recursive = false):void {
|
||||
|
||||
// One reason, to throw an error, is that the folder already exists.
|
||||
if (\is_dir($pathname)) {
|
||||
return;
|
||||
}
|
||||
if (\mkdir($pathname, $mode, $recursive) === false) {
|
||||
throw new Exception("Failed to create directory: $pathname");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around unlink, that throws an exception if the file failed to be
|
||||
* removed.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.unlink.php
|
||||
*
|
||||
* @param string $filename File path.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function unlink(string $filename):void {
|
||||
|
||||
if (\unlink($filename) === false) {
|
||||
throw new Exception("Failed to delete: $filename");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets contents of a folder.
|
||||
*
|
||||
@ -81,7 +126,9 @@ final class MD_STD {
|
||||
public static function ob_get_clean():string {
|
||||
|
||||
$output = \ob_get_clean();
|
||||
if ($output === false) throw new MDOutputBufferNotStarted("Output buffer was not started");
|
||||
if ($output === false) {
|
||||
throw new MDOutputBufferNotStarted("Output buffer was not started");
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
@ -96,8 +143,12 @@ final class MD_STD {
|
||||
*/
|
||||
public static function startsWith(string $haystack, string $needle):bool {
|
||||
|
||||
if (substr($haystack, 0, \strlen($needle)) == $needle) return true;
|
||||
else return false;
|
||||
if (substr($haystack, 0, \strlen($needle)) === $needle) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -114,7 +165,9 @@ final class MD_STD {
|
||||
$output = false;
|
||||
foreach ($needles as $needle) {
|
||||
$output = self::startsWith($haystack, $needle);
|
||||
if ($output == true) return $output;
|
||||
if ($output == true) {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
|
||||
@ -154,7 +207,9 @@ final class MD_STD {
|
||||
public static function json_encode(array $value, int $options = 0, int $depth = 512):string {
|
||||
|
||||
$output = \json_encode($value, $options, $depth);
|
||||
if ($output === false) throw new Exception("JSON output could not be generated");
|
||||
if ($output === false) {
|
||||
throw new Exception("JSON output could not be generated");
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
@ -169,11 +224,45 @@ final class MD_STD {
|
||||
public static function strtotime(string $datetime):int {
|
||||
|
||||
$output = \strtotime($datetime);
|
||||
if ($output === false) throw new MDInvalidInputDate("Invalid input date {$datetime}.");
|
||||
if ($output === false) {
|
||||
throw new MDInvalidInputDate("Invalid input date {$datetime}.");
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a curl request with the given presets.
|
||||
*
|
||||
* @param string $url URL to query.
|
||||
* @param integer $timeout Timeout in milliseconds.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public static function curl_init(string $url, int $timeout) {
|
||||
|
||||
$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');
|
||||
|
||||
/*
|
||||
if (!file_exists(__DIR__ . '/../../curled.txt')) {
|
||||
touch (__DIR__ . '/../../curled.txt');
|
||||
}
|
||||
file_put_contents(__DIR__ . '/../../curled.txt', $url . PHP_EOL, FILE_APPEND);
|
||||
*/
|
||||
|
||||
return $curl;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for curling contents from the web.
|
||||
*
|
||||
@ -184,28 +273,67 @@ final class MD_STD {
|
||||
*/
|
||||
public static function runCurl(string $url, int $timeout = 1200):string {
|
||||
|
||||
$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 = self::curl_init($url, $timeout);
|
||||
\curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
\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');
|
||||
|
||||
$result = \curl_exec($curl);
|
||||
|
||||
// if ($err = curl_errno($curl)) echo $err;
|
||||
// if ($errmsg = curl_error($curl)) echo $errmsg;
|
||||
|
||||
\curl_close($curl);
|
||||
if (\is_bool($result)) return "";
|
||||
if (\is_bool($result)) {
|
||||
return "";
|
||||
}
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param array<string> $urls URL to query.
|
||||
* @param integer $timeout Timeout in milliseconds.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function runCurlMulti(array $urls, int $timeout = 1200):array {
|
||||
|
||||
if (!($mh = curl_multi_init())) {
|
||||
throw new exception("Failed to set up multi handle");
|
||||
}
|
||||
|
||||
$curl_array = [];
|
||||
foreach($urls as $i => $url) {
|
||||
|
||||
$curl_array[$i] = self::curl_init($url, $timeout);
|
||||
|
||||
curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true);
|
||||
curl_multi_add_handle($mh, $curl_array[$i]);
|
||||
|
||||
}
|
||||
|
||||
$running = null;
|
||||
do {
|
||||
usleep(10000);
|
||||
curl_multi_exec($mh, $running);
|
||||
} while($running > 0);
|
||||
|
||||
$res = [];
|
||||
foreach($urls as $i => $url) {
|
||||
$res[$i] = curl_multi_getcontent($curl_array[$i]);
|
||||
}
|
||||
|
||||
foreach($urls as $i => $url){
|
||||
curl_multi_remove_handle($mh, $curl_array[$i]);
|
||||
}
|
||||
curl_multi_close($mh);
|
||||
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function lang_getfrombrowser gets the browser language based on HTTP headers.
|
||||
*
|
||||
@ -221,7 +349,9 @@ final class MD_STD {
|
||||
|
||||
// $_SERVER['HTTP_ACCEPT_LANGUAGE'] verwenden, wenn keine Sprachvariable mitgegeben wurde
|
||||
if ($lang_variable === "") {
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) $lang_variable = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
$lang_variable = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
}
|
||||
}
|
||||
|
||||
// wurde irgendwelche Information mitgeschickt?
|
||||
@ -232,7 +362,9 @@ final class MD_STD {
|
||||
|
||||
// Den Header auftrennen
|
||||
$accepted_languages = preg_split('/,\s*/', $lang_variable);
|
||||
if (!is_array($accepted_languages)) return $default_language;
|
||||
if (!is_array($accepted_languages)) {
|
||||
return $default_language;
|
||||
}
|
||||
|
||||
// Die Standardwerte einstellen
|
||||
$current_lang = $default_language;
|
||||
@ -259,7 +391,8 @@ final class MD_STD {
|
||||
if (isset($matches[2])) {
|
||||
// die Qualität benutzen
|
||||
$lang_quality = (float)$matches[2];
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Kompabilitätsmodus: Qualität 1 annehmen
|
||||
$lang_quality = 1.0;
|
||||
}
|
||||
@ -340,7 +473,9 @@ final class MD_STD {
|
||||
public static function openssl_random_pseudo_bytes(int $length):string {
|
||||
|
||||
$output = \openssl_random_pseudo_bytes($length);
|
||||
if ($output === false) throw new Exception("Failed generating random pseudo bytes using openssl_random_pseudo_bytes");
|
||||
if ($output === false) {
|
||||
throw new Exception("Failed generating random pseudo bytes using openssl_random_pseudo_bytes");
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
@ -356,7 +491,9 @@ final class MD_STD {
|
||||
|
||||
$input = \explode(PHP_EOL, $input);
|
||||
$output = "";
|
||||
foreach ($input as $line) $output .= \trim($line) . PHP_EOL;
|
||||
foreach ($input as $line) {
|
||||
$output .= \trim($line) . PHP_EOL;
|
||||
}
|
||||
return $output;
|
||||
|
||||
}
|
||||
@ -412,7 +549,7 @@ final class MD_STD {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function ensure_file(string $filepath, array $accepted_mimetype = []) {
|
||||
public static function ensure_file(string $filepath, array $accepted_mimetype = []):void {
|
||||
|
||||
if (!\file_exists($filepath)) {
|
||||
throw new MDFileDoesNotExist("File " . basename($filepath) . " does not exist");
|
||||
@ -430,4 +567,57 @@ final class MD_STD {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around exec, to be used with editing functions.
|
||||
* Pipes STDERR to STDOUT and throws an Exception on any error.
|
||||
*
|
||||
* @param string $cmds Commands to run.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function exec_edit(string $cmds):void {
|
||||
|
||||
$error = \shell_exec($cmds . ' 2>&1 1>/dev/null');
|
||||
if (!empty($error)) {
|
||||
throw new \Exception('Shell error: ' . $error . PHP_EOL . PHP_EOL . 'Command was: ' . $cmds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around levenshtein(), that only compares the first 250
|
||||
* characters (levenshtein can't handle more than 255).
|
||||
*
|
||||
* @param string $str1 First string.
|
||||
* @param string $str2 Second string.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function levenshtein(string $str1, string $str2):int {
|
||||
|
||||
if (\strlen($str1) > 250) {
|
||||
$str1 = \substr($str1, 0, 250);
|
||||
}
|
||||
if (\strlen($str2) > 250) {
|
||||
$str2 = \substr($str2, 0, 250);
|
||||
}
|
||||
|
||||
return \levenshtein($str1, $str2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to color codes.
|
||||
*
|
||||
* @param string $str Input string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function string_to_color_code(string $str):string {
|
||||
|
||||
$code = substr(dechex(crc32($str)), 0, 6);
|
||||
return $code;
|
||||
|
||||
}
|
||||
}
|
||||
|
88
MD_STD_CACHE.php
Normal file
88
MD_STD_CACHE.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?PHP
|
||||
/**
|
||||
* Provides static functions for simple caching.
|
||||
*
|
||||
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
|
||||
/**
|
||||
* Provides caching functions.
|
||||
*/
|
||||
final class MD_STD_CACHE {
|
||||
|
||||
/** @var string */
|
||||
public static string $redis_host = '127.0.0.1';
|
||||
/** @var integer */
|
||||
public static int $redis_port = 6379;
|
||||
|
||||
/**
|
||||
* Shutdown function for caching contents of output buffer.
|
||||
*
|
||||
* @param string $redisKey Key to cache by in redis.
|
||||
* @param integer $expiry Expiration time in seconds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function shutdown_cache_through_redis(string $redisKey, int $expiry = 3600):void {
|
||||
|
||||
$outputT = trim(MD_STD::minimizeHTMLString(MD_STD::ob_get_clean()));
|
||||
echo $outputT;
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect(self::$redis_host, self::$redis_port, 1, null, 0, 0, ['auth' => [MD_CONF::$redis_pw]]);
|
||||
$redis->set($redisKey, $outputT);
|
||||
$redis->expire($redisKey, $expiry);
|
||||
$redis->close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches and serves a page through redis. Should be called at the start
|
||||
* of the script generating a page.
|
||||
*
|
||||
* @param string $redisKey Key to cache by in redis.
|
||||
* @param integer $expiry Expiration time in seconds.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function serve_page_through_redis_cache(string $redisKey, int $expiry = 3600):string {
|
||||
|
||||
if (PHP_SAPI === 'cli') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect(self::$redis_host, self::$redis_port, 1, null, 0, 0, ['auth' => [MD_CONF::$redis_pw]]);
|
||||
if ($redis->ping() !== false) {
|
||||
|
||||
ob_start();
|
||||
|
||||
if (($redisResult = $redis->get($redisKey))) {
|
||||
|
||||
if (strlen($redisResult) > 3) {
|
||||
$redis->close();
|
||||
return $redisResult;
|
||||
}
|
||||
else {
|
||||
register_shutdown_function(function(string $redisKey, int $expiry = 3600) :void {
|
||||
self::shutdown_cache_through_redis($redisKey, $expiry);
|
||||
}, $redisKey);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
register_shutdown_function(function(string $redisKey, int $expiry = 3600) :void {
|
||||
self::shutdown_cache_through_redis($redisKey, $expiry);
|
||||
}, $redisKey);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
$redis->close();
|
||||
|
||||
return '';
|
||||
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ declare(strict_types = 1);
|
||||
* functions.
|
||||
*/
|
||||
final class MD_STD_IN {
|
||||
|
||||
/**
|
||||
* Validates and sanitizes input integers to be in line with MySQL
|
||||
* autoincrement IDs.
|
||||
@ -45,7 +44,9 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function sanitize_id_or_zero($input):int {
|
||||
|
||||
if ($input === "") return 0;
|
||||
if ($input === "") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$input = \filter_var($input, \FILTER_VALIDATE_INT, [
|
||||
'options' => [
|
||||
@ -77,7 +78,9 @@ final class MD_STD_IN {
|
||||
FILTER_SANITIZE_STRING,
|
||||
FILTER_FLAG_NO_ENCODE_QUOTES);
|
||||
|
||||
if ($output === false) return "";
|
||||
if ($output === false) {
|
||||
return "";
|
||||
}
|
||||
while (strpos($output, " ") !== false) {
|
||||
$output = str_replace(" ", " ", $output);
|
||||
}
|
||||
@ -86,6 +89,29 @@ final class MD_STD_IN {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($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.
|
||||
@ -104,10 +130,12 @@ final class MD_STD_IN {
|
||||
else if (isset($_POST[$var_name])) {
|
||||
$output = self::sanitize_text($_POST[$var_name]);
|
||||
}
|
||||
else $output = self::sanitize_text($default);
|
||||
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) . "'");
|
||||
throw new MDpageParameterNotFromListException("Parameter `{$var_name}` must be any of the allowed values: '" . implode('\', \'', $allowed) . "'");
|
||||
}
|
||||
|
||||
return $output;
|
||||
@ -129,10 +157,12 @@ final class MD_STD_IN {
|
||||
if (isset($_POST[$var_name])) {
|
||||
$output = self::sanitize_text($_POST[$var_name]);
|
||||
}
|
||||
else $output = self::sanitize_text($default);
|
||||
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) . "'");
|
||||
throw new MDpageParameterNotFromListException("Parameter `{$var_name}` must be any of the allowed values: '" . implode('\', \'', $allowed) . "'");
|
||||
}
|
||||
|
||||
return $output;
|
||||
@ -148,7 +178,9 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function sanitize_url($input):string {
|
||||
|
||||
if ($input === "") return "";
|
||||
if ($input === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
$output = \filter_var($input, FILTER_SANITIZE_URL);
|
||||
if (($output = \filter_var($output, FILTER_VALIDATE_URL)) === false) {
|
||||
@ -168,7 +200,9 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function sanitize_email($input):string {
|
||||
|
||||
if ($input === "") return "";
|
||||
if ($input === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
$output = \filter_var($input, FILTER_SANITIZE_EMAIL);
|
||||
if (($output = \filter_var($output, FILTER_VALIDATE_EMAIL)) === false) {
|
||||
@ -205,7 +239,9 @@ final class MD_STD_IN {
|
||||
*/
|
||||
public static function validate_isbn(string $input):string {
|
||||
|
||||
if ($input === "") return "";
|
||||
if ($input === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Remove hyphens
|
||||
$input = trim(strtr($input, ["-" => "", "–" => ""]));
|
||||
@ -231,5 +267,4 @@ final class MD_STD_IN {
|
||||
throw new MDgenericInvalidInputsException("ISBNs must be either 10 or 13 characters long.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ final class MD_STD_SEC {
|
||||
) {
|
||||
$validity = true;
|
||||
}
|
||||
$_SESSION['csrf-token'] = null; unset($_SESSION['csrf-token']);
|
||||
$_SESSION['csrf-token'] = null;
|
||||
unset($_SESSION['csrf-token']);
|
||||
|
||||
return $validity;
|
||||
|
||||
@ -46,8 +47,8 @@ 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 = 3;
|
||||
const BRUTE_FORCE_DELAY_MULTIPLIER_PER_IP = 8;
|
||||
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 .
|
||||
@ -67,7 +68,9 @@ final class MD_STD_SEC {
|
||||
$logfile_common = \sys_get_temp_dir() . "/logins_{$tool_name}.json";
|
||||
|
||||
// Ensure the log files exist
|
||||
if (!\file_exists($logfile_common)) \file_put_contents($logfile_common, "[]");
|
||||
if (!\file_exists($logfile_common)) {
|
||||
\file_put_contents($logfile_common, "[]");
|
||||
}
|
||||
|
||||
// Hash entered username and IP to prevent malicious strings from
|
||||
// entering the system.
|
||||
@ -102,7 +105,7 @@ final class MD_STD_SEC {
|
||||
// Translate counters into delay multipliers
|
||||
$delay_multiplier_common = $loginLog['common']['count'];
|
||||
$delay_multiplier_per_user = $loginLog['usr'][$hash_user]['count'];
|
||||
$delay_multiplier_per_ip = $loginLog['usr'][$hash_ip]['count'];
|
||||
$delay_multiplier_per_ip = $loginLog['ip'][$hash_ip]['count'];
|
||||
|
||||
// Calculate delay
|
||||
$delay_micoseconds = \intval(self::BRUTE_FORCE_DELAY_DEFAULT *
|
||||
@ -122,4 +125,24 @@ final class MD_STD_SEC {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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\';';
|
||||
|
||||
if (!empty($frame_ancestors)) {
|
||||
$policy .= ' frame-ancestors ' . $frame_ancestors . ';';
|
||||
}
|
||||
|
||||
header($policy);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ declare(strict_types = 1);
|
||||
* Exception thrown by MDJail if a required security option has not been set.
|
||||
*/
|
||||
final class MDJailSecurityOptionNotSetException extends Exception {
|
||||
|
||||
/**
|
||||
* Error message.
|
||||
*
|
||||
@ -17,5 +16,4 @@ final class MDJailSecurityOptionNotSetException extends Exception {
|
||||
return $errorMsg;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user