From 5a2429067a89d57010678dc168b68b23e54d5bc2 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 17 Jun 2026 15:37:45 -0400 Subject: [PATCH] Fun w/ Arrays/JSON --- src/Framework/Common.php | 135 +++++++++++++----- src/Framework/Logger.php | 25 +++- src/Framework/SiteHelper.php | 14 +- .../Trait/Security/CsrfTokenFunctions.php | 31 ++-- 4 files changed, 143 insertions(+), 62 deletions(-) diff --git a/src/Framework/Common.php b/src/Framework/Common.php index 3927717..b3fbece 100644 --- a/src/Framework/Common.php +++ b/src/Framework/Common.php @@ -11,13 +11,14 @@ use IOcornerstone\Framework\{ Enum\ExitOnDump as endDump, }; -final class Common +final class Common { + /** * Clear out from memory given variable by Reference! * @param type $sensitive_data */ - public static function wipe(#[\SensitiveParameter] &$sensitive_data): void + public static function wipe(#[\SensitiveParameter] &$sensitive_data): void { if (function_exists("sodium_memzero")) { sodium_memzero($sensitive_data); @@ -25,29 +26,47 @@ final class Common unset($sensitive_data); } - public static function getCount($i): int + public static function getCount(mixed $i): int { return (is_array($i) || is_object($i)) ? count($i) : 0; } - + + public static function decodeJson(null|string|false $sJson, int $levelsDeep = 100): ?array + { + try { + if ($sJson !== false && $sJson !== null && $sJson !== "" && $sJson !== "[]" && json_validate($sJson, $levelsDeep)) { + $j = json_decode($sJson, associative: true, depth: $levelsDeep); + return $j; + } + } catch (\JsonException $e) { + return null; + } + return null; + } + + public static function isArrayWithData(?array $data): bool + { + return (self::getCount($data) > 0) ? true : false; + } + public static function hasKeys(array $array): bool { return array_keys($array) !== range(0, count($array) - 1); } - + public static function combineDataToString(object $o, ...$args): string { - $stringArgs = array_map(function($arg) { + $stringArgs = array_map(function ($arg) { if (is_array($arg) || is_object($arg)) { $arg = json_encode($arg); } - return (string)$arg; + return (string) $arg; }, $args); - + $seperator = $o->seperator ?? "|"; $combined = implode($seperator, $stringArgs); - + $useLogger = $o->useLogger ?? false; if ($useLogger) { $logger = new Logger(); @@ -61,34 +80,72 @@ final class Common return $combined; } - public static function stringSubPart(string $string, int $offset = 0, ?int $length = null, $encoding = null) { - if ($length === null) { - return F::substr($string, $offset, strlen($string)); - } else { - return F::substr($string, $offset, $length); + public static function doesAllOfTheArrayHaveData(array $a, array $skipKeys = []): false|array + { + if (self::isArrayWithData($a)) { + foreach ($a as $key => $value) { + if ($value === false) { + if ( + self::isArrayWithData($skipKeys) && in_array($key, $skipKeys) + ) { + continue; // In List of keys to Skip, so do so... + } + return false; // Input was false, not set..., so bail as false + } + } + return $a; // All is GOOD here, return the Data BACK } + return false; // Empty Data..., return false } - + + public static function safeFlipArray(?array $data): array + { + if ($data === null) { + return []; + } + + foreach($data as $key => $value) { + if (is_bool($value)) { + $data[$key] = (int) $value; + } + } + $safeData = array_filter($data, function ($value) { + return is_string($value) || is_int($value); + }); + return array_flip($safeData); + } + /** * Will get only left part of string by length. * @param string $str * @param int $length * @retval type string or false */ - public static function getStringLeft(string $str, int $length): false | string { + public static function getStringLeft(string $str, int $length): false|string + { return self::stringSubPart($str, 0, $length); } - + /** * Will get only the right part of string by length. * @param string $str * @param int $length * @retval type string or false */ - public static function getStringRight(string $str, int $length): false | string { + public static function getStringRight(string $str, int $length): false|string + { return self::stringSubPart($str, -$length); } - + + public static function stringSubPart(string $string, int $offset = 0, ?int $length = null, $encoding = null) + { + if ($length === null) { + return F::substr($string, $offset, strlen($string)); + } else { + return F::substr($string, $offset, $length); + } + } + /** * Variable Dump and exit * Configure of security for show_dumps must be true for debugging. @@ -96,14 +153,15 @@ final class Common * @param bool end - if true ends the script */ public static function dump( - $var = 'nothing', - endDump $end = endDump::EXIT_AND_STOP - ): void { + $var = 'nothing', + endDump $end = endDump::EXIT_AND_STOP + ): void + { if (\IOcornerstone\Framework\Configure::get('security', 'show_dumps') !== true) { return; } $isConsole = Console::isConsole(); - if (! $isConsole) { + if (!$isConsole) { echo "
\r\nExpand to see Var Dump:"; echo "

"; var_dump($var); @@ -131,13 +189,13 @@ final class Common } elseif (is_null($var)) { echo 'VAR IS NULL!'; } elseif (is_string($var)) { - if (! $isConsole) { + if (!$isConsole) { echo 'VAR is a STRING = ' . htmlentities($var); } else { echo 'VAR is a STRING = ' . $var; - } + } } else { - if (! $isConsole) { + if (!$isConsole) { echo "

";
                 print_r($var);
                 echo '
'; @@ -146,7 +204,7 @@ final class Common echo PHP_EOL; } } - if (! $isConsole) { + if (!$isConsole) { echo '

'; } @@ -160,7 +218,8 @@ final class Common * So, you need to code more checks! * @retval boolean true if AJAX request by JQuery, etc... */ - public static function isAjax(): bool { + public static function isAjax(): bool + { $http_x_requested_with = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ""; return (strtolower($http_x_requested_with) === 'xmlhttprequest'); } @@ -168,17 +227,19 @@ final class Common /** * site http://php.net/manual/en/function.base64-encode.php */ - public static function base64urlEncode(string $data): string { - return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); + public static function base64urlEncode(string $data): string + { + return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); + } + + public static function base64urlDecode(string $data): string + { + //return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); + return base64_decode(strtr($data, '-_', '+/') . str_repeat('=', 3 - (3 + strlen($data)) % 4)); } - public static function base64urlDecode(string $data): string { - //return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); - return base64_decode( strtr( $data, '-_', '+/') . str_repeat('=', 3 - ( 3 + strlen( $data )) % 4 )); - } - - public static function nl2br(string $text): string + public static function nl2br(string $text): string { return strtr($text, array("\r\n" => '
', "\r" => '
', "\n" => '
')); } -} \ No newline at end of file +} diff --git a/src/Framework/Logger.php b/src/Framework/Logger.php index 9de0164..7e9479d 100644 --- a/src/Framework/Logger.php +++ b/src/Framework/Logger.php @@ -159,7 +159,7 @@ final class Logger implements LoggerInterface } if ( - self::LEVEL_PRIORITY[$level] < self::LEVEL_PRIORITY[$this->minLevel] + self::LEVEL_PRIORITY[$level] < self::LEVEL_PRIORITY[$this->minLevel] ) { return; } @@ -185,7 +185,15 @@ final class Logger implements LoggerInterface } /* ---------------- Level Methods ---------------- */ - + public function msgWithArray($message, array $content = [], array $myArray = []): void + { + if (count($myArray) >0 ) { + $this->log(LogLevel::ALERT, $message . " :array
\r\n " . $this->arrayToString($myArray), $content); + return; + } + $this->log(level: LogLevel::ALERT, message: $message, context: $content); + } + public function emergency($message, array $context = []): void { $this->log(LogLevel::EMERGENCY, $message, $context); @@ -252,6 +260,19 @@ final class Logger implements LoggerInterface return strtr($message, $replace); } + + private function arrayToString(?array $a, string $separator = ", "): string + { + if ($a === null) { + return ""; + } + $s = ""; + foreach($a as $key=>$value) { + $s .= "key: $key value: $value
" . PHP_EOL; + } + return $s; + } + private function getLines(string $file): int { diff --git a/src/Framework/SiteHelper.php b/src/Framework/SiteHelper.php index 30831a8..0c290c9 100644 --- a/src/Framework/SiteHelper.php +++ b/src/Framework/SiteHelper.php @@ -13,6 +13,7 @@ namespace IOcornerstone\Framework; use IOcornerstone\Framework\{ Security, Console, + Common, }; /** * Description of SiteHelper @@ -103,18 +104,9 @@ final class SiteHelper public static function remoteNotAllowedForceLive(): bool { if (Console::isConsole()) { - return false; // false to show errors and dumps + return false; // false to ALWAYs show errors and dumps on CLI } - - $s = $_SESSION['usersRights'] ?? false; - if ($s !== false && strlen($s) > 4) { - $rights = json_decode($s, associative: true); - $flipped = array_flip($rights); - if (isset($flipped['developer'])) { - return false; // false for Developers to see Errors/Logs - } - } - + return (!self::is_allowed()); } diff --git a/src/Framework/Trait/Security/CsrfTokenFunctions.php b/src/Framework/Trait/Security/CsrfTokenFunctions.php index 1e141df..3025fbe 100644 --- a/src/Framework/Trait/Security/CsrfTokenFunctions.php +++ b/src/Framework/Trait/Security/CsrfTokenFunctions.php @@ -10,11 +10,15 @@ declare(strict_types=1); namespace IOcornerstone\Framework\Trait\Security; -use IOcornerstone\Framework\Configure; +use IOcornerstone\Framework\{ + Configure, + Common, +}; + trait CsrfTokenFunctions { - + const CSRF_TOKEN_POOL_SIZE_LIMIT = 15; // Total Sessions to Keep alive /** * Set Session to use CSRF Token * Useful for JSON data... @@ -30,16 +34,6 @@ trait CsrfTokenFunctions return $newToken; } - /** - * Keep only last 15 tokens to prevent memory issues. - */ - public static function cleanUp(){ - $keepOnly = 15; - if (count($_SESSION['csrf_pool']) > $keepOnly) { - $_SESSION['csrf_pool'] = array_slice($_SESSION['csrf_pool'], -$keepOnly, null, true); - } - } - /** * Get CSRF Token for use with HTML Form * @return string Hidden Form with token set @@ -97,6 +91,19 @@ trait CsrfTokenFunctions unset($_SESSION['csrf_pool'][$key]); } } + self::cleanUp(); + } + + /** + * Keep only last CSRF_TOKEN_POOL_SIZE_LIMIT tokens to prevent memory issues. + */ + private static function cleanUp(): void + { + if (Common::getCount($_SESSION['csrf_pool']) > + self::CSRF_TOKEN_POOL_SIZE_LIMIT + ) { + $_SESSION['csrf_pool'] = array_slice($_SESSION['csrf_pool'], -self::CSRF_TOKEN_POOL_SIZE_LIMIT, null, true); + } } private static function csrfTokenIsValid(string $csrfTokenKeyName = ""): false|int