Compare commits

...

11 Commits

Author SHA1 Message Date
Clemens Schwaighofer
c81b602657 phpunit: redirect error_log message to temp file so they are not printed to console
This is for any logging part that logs to emergency where emergency logging is
set to log to the error_log too
2025-10-09 15:05:00 +09:00
Clemens Schwaighofer
59cc5f2060 phpstan checks and fixes 2025-10-09 11:58:47 +09:00
Clemens Schwaighofer
e072aaf4d6 Add ISO Type datetime format to support, and make this default loggint time format 2025-10-09 11:14:06 +09:00
Clemens Schwaighofer
259f9cebf3 Had to roll back previous MessageLevel changes
Keep everything lower case as is
any upper case check have to go through fromName, this will convert to lowercase anyway
2025-09-10 13:41:42 +09:00
Clemens Schwaighofer
bd4f674f0f Add a noset level and add uppercase support to fromName()
Noset is for unset status, which is different from unknown.
Also allow upper case so we can use "OK" and "ERROR" in addition to "ok" and "error".
2025-09-10 13:28:39 +09:00
Clemens Schwaighofer
87293bf633 Add a security info md file 2025-08-26 14:14:36 +09:00
Clemens Schwaighofer
be46d6e101 Readme update for url fix for the JS utils files 2025-08-18 09:36:10 +09:00
Clemens Schwaighofer
433bc3d539 All array variable names are no longer $array to not confuse 2025-07-23 15:22:25 +09:00
Clemens Schwaighofer
4ed645bac3 Update email check with better domain name check (ASCII), logging class debug output update 2025-07-15 13:13:11 +09:00
Clemens Schwaighofer
908376c1a5 Array sort method doc update 2025-06-26 11:43:28 +09:00
Clemens Schwaighofer
c329e7a2da Add JSON_UNESCAPED_UNICODE as default flag for json convert to array calls 2025-06-26 11:39:38 +09:00
17 changed files with 185 additions and 98 deletions

View File

@@ -24,12 +24,12 @@ final class CoreLibsCheckEmailTest extends TestCase
'get email regex invalid -1, will be 0' => [
-1,
"^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$"
. "(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$"
],
'get email regex invalid 10, will be 0' => [
10,
"^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$"
. "(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$"
],
'get email regex valid 1, will be 1' => [
1,
@@ -157,7 +157,7 @@ final class CoreLibsCheckEmailTest extends TestCase
'error' => 0,
'message' => 'Invalid email address',
'regex' => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$"
. "(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$"
]
],
'error 1 will return double @ error' => [
@@ -181,7 +181,7 @@ final class CoreLibsCheckEmailTest extends TestCase
[
'error' => 3,
'message' => 'Invalid domain part after @ sign',
'regex' => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.([a-zA-Z]{2,}){1}$"
'regex' => "@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$"
]
],
'error 4 will be invalid domain' => [
@@ -189,7 +189,7 @@ final class CoreLibsCheckEmailTest extends TestCase
[
'error' => 4,
'message' => 'Invalid domain name part',
'regex' => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\."
'regex' => "@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\."
]
],
'error 5 will be invalid domain top level only' => [
@@ -197,7 +197,7 @@ final class CoreLibsCheckEmailTest extends TestCase
[
'error' => 5,
'message' => 'Wrong domain top level part',
'regex' => "\.([a-zA-Z]{2,6}){1}$"
'regex' => "\.[a-zA-Z]{2,6}$"
]
],
'error 6 will be domain double dot' => [

View File

@@ -105,11 +105,15 @@ final class CoreLibsLoggingErrorMessagesTest extends TestCase
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Error,
]);
$errorLogTmpfile = tmpfile();
$errorLogLocationBackup = ini_set('error_log', stream_get_meta_data($errorLogTmpfile)['uri']);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setMessage(
$level,
$str
);
// for exceptions if log level is set to catch them
$error_log_content = stream_get_contents($errorLogTmpfile);
$this->assertEquals(
[
'level' => $expected,
@@ -377,6 +381,8 @@ final class CoreLibsLoggingErrorMessagesTest extends TestCase
?bool $log_warning,
string $expected
): void {
$errorLogTmpfile = tmpfile();
$errorLogLocationBackup = ini_set('error_log', stream_get_meta_data($errorLogTmpfile)['uri']);
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesLogError',
'log_folder' => self::LOG_FOLDER,
@@ -392,6 +398,9 @@ final class CoreLibsLoggingErrorMessagesTest extends TestCase
log_error: $log_error,
log_warning: $log_warning
);
ini_set('error_log', $errorLogLocationBackup);
// for exceptions if log level is set to catch them
$error_log_content = stream_get_contents($errorLogTmpfile);
$file_content = '';
if (is_file($log->getLogFolder() . $log->getLogFile())) {
$file_content = file_get_contents(
@@ -447,6 +456,8 @@ final class CoreLibsLoggingErrorMessagesTest extends TestCase
'log_level' => Level::Debug,
'log_per_run' => true
]);
$errorLogTmpfile = tmpfile();
$errorLogLocationBackup = ini_set('error_log', stream_get_meta_data($errorLogTmpfile)['uri']);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
@@ -456,6 +467,9 @@ final class CoreLibsLoggingErrorMessagesTest extends TestCase
log_error: $log_error,
log_warning: $log_warning
);
ini_set('error_log', $errorLogLocationBackup);
// for exceptions if log level is set to catch them
$error_log_content = stream_get_contents($errorLogTmpfile);
$file_content = '';
if (is_file($log->getLogFolder() . $log->getLogFile())) {
$file_content = file_get_contents(

View File

@@ -18,7 +18,7 @@ use CoreLibs\Logging\Logger\Flag;
final class CoreLibsLoggingLoggingTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
private const REGEX_BASE = "\[[\d\-\s\.:]+\]\s{1}" // date
private const REGEX_BASE = "\[[\d\-\s\.:+T]+\]\s{1}" // date, just basic checks
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
. "\[(phar:\/\/)?[\w\-\.\/]+:\d+\]\s{1}" // folder/file [note phar:// is for phpunit]
. "\[\w+\]\s{1}" // run id

View File

@@ -119,6 +119,8 @@ On a version update the old phpunit folder in .libs has to be removed and the ne
The original edit.js javascript functions are now in utils.js or utils.min.js.
The development for thos files is located in a different repository
The development for those files is located in a different repository
https://[service]/CodeBlocks/javascript-utils
General: <https://[service]/CodeBlocks/JavaScript.utils>
Org: <https://[serverice]/[org]/Code-Blocks.JavaScript.utils>

11
SECURITY.md Normal file
View File

@@ -0,0 +1,11 @@
# Security Policy
This software follows the [Semver 2.0 scheme](https://semver.org/).
## Supported Versions
Only the latest version is supported
## Reporting a Vulnerability
Open a ticket to report a secuirty problem

View File

@@ -332,7 +332,7 @@ print "(kosrt, lower case, reverse): "
print "<hr>";
$nested = [
'B' => 'foo', 'a', '0', 9,
'B' => 'foo', 'a', '0', 9, /** @phpstan-ignore-line This is a test for wrong index */
'1' => ['z', 'b', 'a'],
'd' => ['zaip', 'bar', 'baz']
];

View File

@@ -68,6 +68,14 @@ function test2(): array
return DebugSupport::getCallerMethodList(1);
}
// date stueff
print "printTime(-1): " . DebugSupport::printTime() . "<br>";
print "printTime(2): " . DebugSupport::printTime(2) . "<br>";
print "printTime(3): " . DebugSupport::printTime(3) . "<br>";
print "printTime(5): " . DebugSupport::printTime(5) . "<br>";
print "printIsoTime(): " . DebugSupport::printIsoTime() . "<br>";
print "printIsoTime(false): " . DebugSupport::printIsoTime(false) . "<br>";
print "S::GETCALLERMETHOD: " . DebugSupport::getCallerMethod(0) . "<br>";
print "S::GETCALLERMETHOD: " . test() . "<br>";
print "S::GETCALLERMETHODLIST: <pre>" . print_r(test2(), true) . "</pre><br>";
@@ -146,7 +154,7 @@ print "LOG LEVEL: " . DebugSupport::printAr(\CoreLibs\Convert\SetVarType::setAr
$new_log->getLogLevel('debug', 'on')
)) . "<br>";
echo "<b>CLASS DEBUG CALL</b><br>";
echo "<b>CLASS DEBUG CALL LEGACY</b><br>";
// @codingStandardsIgnoreLine
class TestL

View File

@@ -40,6 +40,8 @@ print "Log ERROR: " . $log->prAr($em->getFlagLogError()) . "<br>";
print "FN: " . ml::fromName('Affe')->name . "<br>";
print "NU: " . ml::fromValue(100)->name . "<br>";
print "NU: " . ml::fromValue(1000)->name . "<br>";
print "OK.: " . ml::ok->name . "<br>";
print "OK^: " . ml::fromName('OK')->name . "<br>";
$em->setErrorMsg('123', 'error', 'msg this is bad, auto logged if debug');
$em->setErrorMsg('123', 'error', 'msg this is bad, auto logged if debug', 'target-id', 'other-style');

View File

@@ -10,12 +10,16 @@ class Email
/** @var array<int,string> */
private static array $email_regex_check = [
0 => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$", // MASTER
// . "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$", // MASTER
// fixed pattern matching for domain
. "(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$", // MASTER
1 => "@(.*)@(.*)", // double @
2 => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@", // wrong part before @
3 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.([a-zA-Z]{2,}){1}$", // wrong part after @
4 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.", // wrong domain name part
5 => "\.([a-zA-Z]{2,6}){1}$", // wrong top level part
// 3 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.([a-zA-Z]{2,}){1}$", // wrong part after @
3 => "@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$", // wrong part after @
// 4 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.", // wrong domain name part
4 => "@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.", // wrong domain name part
5 => "\.[a-zA-Z]{2,6}$", // wrong top level part
6 => "@(.*)\.{2,}", // double .. in domain name part
7 => "@.*\.$" // ends with a dot, top level, domain missing
];

View File

@@ -150,14 +150,14 @@ class ArrayHandler
* array search simple. looks for key, value combination, if found, returns true
* on default does not strict check, so string '4' will match int 4 and vica versa
*
* @param array<mixed> $array search in as array
* @param array<mixed> $in_array search in as array
* @param string|int $key key (key to search in)
* @param string|int|bool|array<string|int|bool> $value values list (what to find)
* @param bool $strict [false], if set to true, will strict check key/value
* @return bool true on found, false on not found
*/
public static function arraySearchSimple(
array $array,
array $in_array,
string|int $key,
string|int|bool|array $value,
bool $strict = false
@@ -166,7 +166,7 @@ class ArrayHandler
if (!is_array($value)) {
$value = [$value];
}
foreach ($array as $_key => $_value) {
foreach ($in_array as $_key => $_value) {
// if value is an array, we search
if (is_array($_value)) {
// call recursive, and return result if it is true, else continue
@@ -189,19 +189,19 @@ class ArrayHandler
* If prefix is turned on each found group will be prefixed with the
* search key
*
* @param array<mixed> $array array to search in
* @param array<mixed> $in_array array to search in
* @param array<mixed> $needles keys to find in array
* @param bool $flat [false] Turn on flat output
* @param bool $prefix [false] Prefix found with needle key
* @return array<mixed> Found values
*/
public static function arraySearchKey(
array $array,
array $in_array,
array $needles,
bool $flat = false,
bool $prefix = false
): array {
$iterator = new \RecursiveArrayIterator($array);
$iterator = new \RecursiveArrayIterator($in_array);
$recursive = new \RecursiveIteratorIterator(
$iterator,
\RecursiveIteratorIterator::SELF_FIRST
@@ -248,7 +248,7 @@ class ArrayHandler
* If not found return an array with the array block there the required key is missing,
* the path as string with seperator block set and the missing key entry
*
* @param array<mixed> $array
* @param array<mixed> $in_array
* @param string|int|float|bool $search_value
* @param string|array<string> $required_key
* @param ?string $search_key [null]
@@ -257,7 +257,7 @@ class ArrayHandler
* @return array<array{content?:array<mixed>,path?:string,missing_key?:array<string>}>
*/
public static function findArraysMissingKey(
array $array,
array $in_array,
string|int|float|bool $search_value,
string|array $required_key,
?string $search_key = null,
@@ -265,7 +265,7 @@ class ArrayHandler
string $current_path = ''
): array {
$results = [];
foreach ($array as $key => $value) {
foreach ($in_array as $key => $value) {
$path = $current_path ? $current_path . $path_separator . $key : $key;
if (is_array($value)) {
@@ -321,7 +321,7 @@ class ArrayHandler
* Find key => value entry and return set with key for all matching
* Can search recursively through nested arrays if recursive flag is set
*
* @param array<mixed> $array
* @param array<mixed> $in_array
* @param string $lookup
* @param int|string|float|bool $search
* @param bool $strict [false]
@@ -332,7 +332,7 @@ class ArrayHandler
* @return array<mixed>
*/
public static function selectArrayFromOption(
array $array,
array $in_array,
string $lookup,
int|string|float|bool $search,
bool $strict = false,
@@ -342,7 +342,7 @@ class ArrayHandler
string $flat_separator = self::DATA_SEPARATOR
): array {
// skip on empty
if ($array == []) {
if ($in_array == []) {
return [];
}
// init return result
@@ -352,7 +352,7 @@ class ArrayHandler
$search = strtolower($search);
}
foreach ($array as $key => $value) {
foreach ($in_array as $key => $value) {
// Handle current level search
if (isset($value[$lookup])) {
$compareValue = $value[$lookup];
@@ -399,14 +399,14 @@ class ArrayHandler
/**
* main wrapper function for next/prev key
*
* @param array<mixed> $array array to search in
* @param array<mixed> $in_array array to search in
* @param int|string $key key for next/prev
* @param bool $next [=true] if to search next or prev
* @return int|string|null Next/prev key or null for end/first
*/
private static function arrayGetKey(array $array, int|string $key, bool $next = true): int|string|null
private static function arrayGetKey(array $in_array, int|string $key, bool $next = true): int|string|null
{
$keys = array_keys($array);
$keys = array_keys($in_array);
if (($position = array_search($key, $keys, true)) === false) {
return null;
}
@@ -422,26 +422,26 @@ class ArrayHandler
* Get previous array key from an array
* null on not found
*
* @param array<mixed> $array
* @param array<mixed> $in_array
* @param int|string $key
* @return int|string|null Next key, or null for not found
*/
public static function arrayGetPrevKey(array $array, int|string $key): int|string|null
public static function arrayGetPrevKey(array $in_array, int|string $key): int|string|null
{
return self::arrayGetKey($array, $key, false);
return self::arrayGetKey($in_array, $key, false);
}
/**
* Get next array key from an array
* null on not found
*
* @param array<mixed> $array
* @param array<mixed> $in_array
* @param int|string $key
* @return int|string|null Next key, or null for not found
*/
public static function arrayGetNextKey(array $array, int|string $key): int|string|null
public static function arrayGetNextKey(array $in_array, int|string $key): int|string|null
{
return self::arrayGetKey($array, $key, true);
return self::arrayGetKey($in_array, $key, true);
}
/**
@@ -463,27 +463,27 @@ class ArrayHandler
}
// default key is not string
$key_is_string = false;
$arrays = func_get_args();
$in_arrays = func_get_args();
// if last is not array, then assume it is trigger for key is always string
if (!is_array(end($arrays))) {
if (array_pop($arrays)) {
if (!is_array(end($in_arrays))) {
if (array_pop($in_arrays)) {
$key_is_string = true;
}
}
// check that arrays count is at least two, else we don't have enough to do anything
if (count($arrays) < 2) {
if (count($in_arrays) < 2) {
throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
}
$merged = [];
while ($arrays) {
$array = array_shift($arrays);
if (!is_array($array)) {
while ($in_arrays) {
$in_array = array_shift($in_arrays);
if (!is_array($in_array)) {
throw new \TypeError(__FUNCTION__ . ' encountered a non array argument');
}
if (!$array) {
if (!$in_array) {
continue;
}
foreach ($array as $key => $value) {
foreach ($in_array as $key => $value) {
// if string or if key is assumed to be string do key match
// else add new entry
if (is_string($key) || $key_is_string === false) {
@@ -589,14 +589,14 @@ class ArrayHandler
* converts multi dimensional array to a flat array
* does NOT preserve keys
*
* @param array<mixed> $array multi dimensionial array
* @param array<mixed> $in_array multi dimensionial array
* @return array<mixed> flattened array
*/
public static function flattenArray(array $array): array
public static function flattenArray(array $in_array): array
{
$return = [];
array_walk_recursive(
$array,
$in_array,
function ($value) use (&$return) {
$return[] = $value;
}
@@ -607,13 +607,13 @@ class ArrayHandler
/**
* will loop through an array recursivly and write the array keys back
*
* @param array<mixed> $array multidemnsional array to flatten
* @param array<mixed> $in_array multidemnsional array to flatten
* @param array<mixed> $return recoursive pass on array of keys
* @return array<mixed> flattened keys array
*/
public static function flattenArrayKey(array $array, array $return = []): array
public static function flattenArrayKey(array $in_array, array $return = []): array
{
foreach ($array as $key => $sub) {
foreach ($in_array as $key => $sub) {
$return[] = $key;
if (is_array($sub) && count($sub) > 0) {
$return = self::flattenArrayKey($sub, $return);
@@ -626,14 +626,14 @@ class ArrayHandler
* as above will flatten an array, but in this case only the outmost
* leave nodes, all other keyswill be skipped
*
* @param array<mixed> $array multidemnsional array to flatten
* @param array<mixed> $in_array multidemnsional array to flatten
* @return array<mixed> flattened keys array
*/
public static function flattenArrayKeyLeavesOnly(array $array): array
public static function flattenArrayKeyLeavesOnly(array $in_array): array
{
$return = [];
array_walk_recursive(
$array,
$in_array,
function ($value, $key) use (&$return) {
$return[] = $key;
}
@@ -645,14 +645,14 @@ class ArrayHandler
* searches for key -> value in an array tree and writes the value one level up
* this will remove this leaf will all other values
*
* @param array<mixed> $array nested array
* @param array<mixed> $in_array nested array
* @param string|int $search key to find that has no sub leaf
* and will be pushed up
* @return array<mixed> modified, flattened array
*/
public static function arrayFlatForKey(array $array, string|int $search): array
public static function arrayFlatForKey(array $in_array, string|int $search): array
{
foreach ($array as $key => $value) {
foreach ($in_array as $key => $value) {
// if it is not an array do just nothing
if (!is_array($value)) {
continue;
@@ -660,14 +660,14 @@ class ArrayHandler
// probe it has search key
if (isset($value[$search])) {
// set as current
$array[$key] = $value[$search];
$in_array[$key] = $value[$search];
} else {
// call up next node down
// $array[$key] = call_user_func(__METHOD__, $value, $search);
$array[$key] = self::arrayFlatForKey($value, $search);
// $in_array[$key] = call_user_func(__METHOD__, $value, $search);
$in_array[$key] = self::arrayFlatForKey($value, $search);
}
}
return $array;
return $in_array;
}
/**
@@ -677,13 +677,13 @@ class ArrayHandler
*
* https://stackoverflow.com/a/369608
*
* @param array<mixed> $array Array where elements are located
* @param array<mixed> $in_array Array where elements are located
* @param array<mixed> $remove Elements to remove
* @return array<mixed> Array with $remove elements removed
*/
public static function arrayRemoveEntry(array $array, array $remove): array
public static function arrayRemoveEntry(array $in_array, array $remove): array
{
return array_diff($array, $remove);
return array_diff($in_array, $remove);
}
/**
@@ -693,20 +693,20 @@ class ArrayHandler
* key list is a list[string]
* if key list is empty, return array as is
*
* @param array<string,mixed> $array
* @param array<string,mixed> $in_array
* @param array<string> $key_list
* @return array<string,mixed>
*/
public static function arrayReturnMatchingKeyOnly(
array $array,
array $in_array,
array $key_list
): array {
// on empty return as is
if (empty($key_list)) {
return $array;
return $in_array;
}
return array_filter(
$array,
$in_array,
fn($key) => in_array($key, $key_list),
ARRAY_FILTER_USE_KEY
);
@@ -748,16 +748,19 @@ class ArrayHandler
* sort ascending or descending with or without lower case convert
* value only, will loose key connections unless preserve_keys is set to true
*
* @param array<mixed> $array array to sort by values
* @param int $params sort flags
* @param array<mixed> $in_array Array to sort by values
* @param bool $case_insensitive [false] Sort case insensitive
* @param bool $reverse [false] Reverse sort
* @param bool $maintain_keys [false] Maintain keys
* @param int $flag [SORT_REGULAR] Sort flags
* @return array<mixed>
*/
public static function sortArray(
array $array,
array $in_array,
bool $case_insensitive = false,
bool $reverse = false,
bool $maintain_keys = false,
int $params = SORT_REGULAR
int $flag = SORT_REGULAR
): array {
$fk_sort_lower_case = function (string $a, string $b): int {
return strtolower($a) <=> strtolower($b);
@@ -767,26 +770,26 @@ class ArrayHandler
};
$case_insensitive ? (
$maintain_keys ?
(uasort($array, $reverse ? $fk_sort_lower_case_reverse : $fk_sort_lower_case)) :
(usort($array, $reverse ? $fk_sort_lower_case_reverse : $fk_sort_lower_case))
(uasort($in_array, $reverse ? $fk_sort_lower_case_reverse : $fk_sort_lower_case)) :
(usort($in_array, $reverse ? $fk_sort_lower_case_reverse : $fk_sort_lower_case))
) :
(
$maintain_keys ?
($reverse ? arsort($array, $params) : asort($array, $params)) :
($reverse ? rsort($array, $params) : sort($array, $params))
($reverse ? arsort($in_array, $flag) : asort($in_array, $flag)) :
($reverse ? rsort($in_array, $flag) : sort($in_array, $flag))
);
return $array;
return $in_array;
}
/**
* sort by key ascending or descending and return
*
* @param array<mixed> $array
* @param bool $case_insensitive [false]
* @param bool $reverse [false]
* @param array<mixed> $in_array Array to srt
* @param bool $case_insensitive [false] Sort keys case insenstive
* @param bool $reverse [false] Reverse key sort
* @return array<mixed>
*/
public static function ksortArray(array $array, bool $case_insensitive = false, bool $reverse = false): array
public static function ksortArray(array $in_array, bool $case_insensitive = false, bool $reverse = false): array
{
$fk_sort_lower_case = function (string $a, string $b): int {
return strtolower($a) <=> strtolower($b);
@@ -801,12 +804,12 @@ class ArrayHandler
return $b <=> $a;
};
uksort(
$array,
$in_array,
$case_insensitive ?
($reverse ? $fk_sort_lower_case_reverse : $fk_sort_lower_case) :
($reverse ? $fk_sort_reverse : $fk_sort)
);
return $array;
return $in_array;
}
}

View File

@@ -55,10 +55,10 @@ class Json
* Deos not throw errors
*
* @param array<mixed> $data
* @param int $flags json_encode flags as is
* @param int $flags [JSON_UNESCAPED_UNICODE] json_encode flags as is
* @return string JSON string or '{}' if false
*/
public static function jsonConvertArrayTo(array $data, int $flags = 0): string
public static function jsonConvertArrayTo(array $data, int $flags = JSON_UNESCAPED_UNICODE): string
{
$json_string = json_encode($data, $flags) ?: '{}';
self::$json_last_error = json_last_error();

View File

@@ -199,15 +199,17 @@ class Math
callback: fn ($col) => is_array($row) ?
array_reduce(
array: $row,
callback: fn ($a, $v, $i = null) => $a + $v * (
// TODO check that v is not an array
callback: fn ($a, $v, $i = null) => $a + $v * ( /** @phpstan-ignore-line Possible array + int */
// if last entry missing for full copy add a 0 to it
$col[$i ?? array_search($v, $row, true)] ?? 0 /** @phpstan-ignore-line */
$col[$i ?? array_search($v, $row, true)] ?? 0
),
initial: 0,
) :
array_reduce(
array: $col,
callback: fn ($a, $v) => $a + $v * $row,
// TODO check that v is not an array
callback: fn ($a, $v) => $a + $v * $row, /** @phpstan-ignore-line Possible array + int */
initial: 0,
),
array: $bCols,

View File

@@ -263,11 +263,11 @@ class ConvertPlaceholder
}
}
// add the connectors back (1), and the data sets only if no replacement will be done
return $params_lookup[$match] ??
return $params_lookup[$match]/* ??
throw new \RuntimeException(
'Cannot lookup ' . $match . ' in params lookup list',
211
);
)*/;
},
$converted_placeholders['original']['query']
);
@@ -327,11 +327,11 @@ class ConvertPlaceholder
}
}
// add the connectors back (1), and the data sets only if no replacement will be done
return $params_lookup[$match] ??
return $params_lookup[$match]/* ??
throw new \RuntimeException(
'Cannot lookup ' . $match . ' in params lookup list',
231
);
)*/;
},
$converted_placeholders['original']['query']
);

View File

@@ -33,6 +33,36 @@ class Support
return $string;
}
/**
* print ISO type datetime with microseconds and timezone
* Y-m-dTH:i:s.uP
* if no micro time the ".u" part is omitted
*
* @param bool $set_micro_time
* @return string
*/
public static function printIsoTime(bool $set_micro_time = true): string
{
$datetime = new \DateTime();
// Format the DateTime object to ISO 8601 with microseconds
// 'Y-m-d\TH:i:s.uP' is the format string:
// Y: Full year (e.g., 2025)
// m: Month (01-12)
// d: Day of the month (01-31)
// T: Literal 'T' to separate date and time (escaped with a backslash)
// H: Hour (00-23)
// i: Minute (00-59)
// s: Second (00-59)
// u: Microseconds (e.g., 654321)
// P: Difference to Greenwich time (GMT) with colon (e.g., +09:00)
if ($set_micro_time) {
return $datetime->format('Y-m-d\TH:i:s.uP');
} else {
return $datetime->format('Y-m-d\TH:i:sP');
}
}
/**
* prints a html formatted (pre) data
*

View File

@@ -112,7 +112,7 @@ enum Level: int
}
/**
* Returns true if the passed $level is higher or equal to $this
* Returns true if the passed $level is included in set level
*
* @param Level $level
* @return bool

View File

@@ -13,6 +13,7 @@ namespace CoreLibs\Logging\Logger;
enum MessageLevel: int
{
case noset = 0;
case ok = 100;
case success = 150; // special for file uploads
case info = 200;

View File

@@ -96,6 +96,11 @@ class Logging
'type' => 'bool', 'mandatory' => false,
'default' => false, 'deprecated' => true, 'use' => 'log_per_date'
],
// if turned off uses old time format without time zone
'log_time_format_iso' => [
'type' => 'bool', 'mandatory' => false,
'default' => true, 'deprecated' => false
]
];
// options
@@ -646,7 +651,11 @@ class Logging
}
// print "CLASS: " . $class . "<br>";
// get timestamp
$timestamp = Support::printTime();
if (!empty($this->options['log_time_format_iso'])) {
$timestamp = Support::printIsoTime();
} else {
$timestamp = Support::printTime();
}
// if group id is empty replace it with current level
$group_str = $level->getName();
@@ -1475,14 +1484,15 @@ class Logging
Level::Error, Level::Critical, Level::Alert, Level::Emergency
] as $l
) {
print "Check: " . $this->log_level->getName() . " | " . $l->getName() . "<br>";
if ($this->log_level->isHigherThan($l)) {
print "L: " . $this->log_level->getName() . " > " . $l->getName() . "<br>";
print "L(gt): " . $this->log_level->getName() . " > " . $l->getName() . "<br>";
}
if ($this->log_level->includes($l)) {
print "L: " . $this->log_level->getName() . " <= " . $l->getName() . "<br>";
print "L(le): " . $this->log_level->getName() . " <= " . $l->getName() . "<br>";
}
if ($this->log_level->isLowerThan($l)) {
print "L: " . $this->log_level->getName() . " < " . $l->getName() . "<br>";
print "L(lt): " . $this->log_level->getName() . " < " . $l->getName() . "<br>";
}
echo "<br>";
}