Compare commits

...

24 Commits

Author SHA1 Message Date
7b49394c5a Logging/ErrorMessage class 2023-09-08 18:38:19 +09:00
f624776397 Release: v9.6.2 2023-09-08 18:31:03 +09:00
5e31559c3e Release: v9.6.1: wrong 2023-09-05 15:14:04 +09:00
52a7f1197b Fixs in SetType class for string/int/numeric 2023-09-05 14:30:03 +09:00
e1466432a8 Release: v9.6.0 2023-09-01 18:34:22 +09:00
c57e798591 Add proper Exceptions to class instead of false return on critical problems 2023-09-01 18:32:57 +09:00
8126f08b8c Update publish script and zip file location
All zip files are now in published/package-download/
Move the download file name to the .env file in GITEA_UPLOAD_FILENAME
2023-09-01 09:57:05 +09:00
6f657f2890 Release: v9.5.1 2023-08-28 09:54:02 +09:00
92214ae136 DB\IO bug fixes for unset returns 2023-08-28 09:52:51 +09:00
71f9afd6c7 Release: v9.5.0 2023-08-22 13:36:08 +09:00
11de4f9915 Logging update for class/method trace 2023-08-22 13:34:43 +09:00
dfb46d4f4a Release: v9.4.0 2023-08-22 13:33:08 +09:00
53c7dda9a0 JSON Array to convert fix, bool/false return fix 2023-08-02 16:34:57 +09:00
daf2706e7e Release: v9.3.6 2023-07-26 12:13:59 +09:00
6d3a7b7b28 ACL\Login bug fix for acl:base must always be int 2023-07-26 11:52:53 +09:00
745340a7f5 Release: v9.3.5 2023-07-24 09:16:09 +09:00
419c578c46 ACL\Login get edit access id return value fix 2023-07-24 09:14:16 +09:00
6beff9c6ac Release: v9.3.4 2023-07-21 19:07:40 +09:00
79dbd053fa Remove per class loggingn from ACL\Login 2023-07-21 19:06:30 +09:00
74004e5221 Release: v9.3.3 2023-07-21 17:53:18 +09:00
0392187299 DB\IO init with null 2023-07-21 17:52:16 +09:00
edcc65df3e Release: v9.3.2 2023-07-21 17:49:09 +09:00
5dde52a309 DB\IO error/warning log prefix remove, Admin\Backend acl default value check 2023-07-14 15:10:03 +09:00
5f223fb50d Release: v9.3.1 2023-07-04 11:47:24 +09:00
43 changed files with 1909 additions and 570 deletions

View File

@@ -0,0 +1,123 @@
<?php
/**
* This configuration will be read and overlaid on top of the
* default configuration. Command line arguments will be applied
* after this file is read.
*
* @see src/Phan/Config.php
* See Config for all configurable options.
*
* A Note About Paths
* ==================
*
* Files referenced from this file should be defined as
*
* ```
* Config::projectPath('relative_path/to/file')
* ```
*
* where the relative path is relative to the root of the
* project which is defined as either the working directory
* of the phan executable or a path passed in via the CLI
* '-d' flag.
*/
use Phan\Config;
return [
// "target_php_version" => "8.2",
// turn color on (-C)
"color_issue_messages_if_supported" => true,
// If true, missing properties will be created when
// they are first seen. If false, we'll report an
// error message.
"allow_missing_properties" => false,
// Allow null to be cast as any type and for any
// type to be cast to null.
"null_casts_as_any_type" => false,
// Backwards Compatibility Checking
'backward_compatibility_checks' => false,
// Run a quick version of checks that takes less
// time
"quick_mode" => false,
// Only emit critical issues to start with
// (0 is low severity, 5 is normal severity, 10 is critical)
"minimum_severity" => 0,
// enable for dead code check
// this will spill out errors for all methods never called
// use after all is OK to try to find unused code blocks
// ignore recommended: PhanUnreferencedPublicMethod
// "dead_code_detection" => true,
// default false for include path check
"enable_include_path_checks" => true,
"include_paths" => [
'.',
// '../test/configs/'
],
'ignore_undeclared_variables_in_global_scope' => true,
"file_list" => [
"./test/configs/config.php",
// "./test/configs/config.db.php",
// "./test/configs/config.host.php",
// "./test/configs/config.path.php",
"./test/configs/config.other.php",
"./test/configs/config.master.php",
],
// A list of directories that should be parsed for class and
// method information. After excluding the directories
// defined in exclude_analysis_directory_list, the remaining
// files will be statically analyzed for errors.
//
// Thus, both first-party and third-party code being used by
// your application should be included in this list.
'directory_list' => [
// Change this to include the folders you wish to analyze
// (and the folders of their dependencies)
'src',
// To speed up analysis, we recommend going back later and
// limiting this to only the vendor/ subdirectories your
// project depends on.
// `phan --init` will generate a list of folders for you
'vendor/egrajp/smarty-extended',
],
// A list of directories holding code that we want
// to parse, but not analyze
"exclude_analysis_directory_list" => [
'vendor/egrajp/smarty-extended',
],
'exclude_file_list' => [
],
// what not to show as problem
'suppress_issue_types' => [
// 'PhanUndeclaredMethod',
'PhanEmptyFile',
// ignore unreferences public methods, etc here (for dead code check)
'PhanUnreferencedPublicMethod',
'PhanUnreferencedClass',
'PhanWriteOnlyPublicProperty',
'PhanUnreferencedConstant',
'PhanWriteOnlyPublicProperty',
'PhanReadOnlyPublicProperty',
// start ignore annotations
'PhanUnextractableAnnotationElementName',
'PhanUnextractableAnnotationSuffix',
],
// Override to hardcode existence and types of (non-builtin) globals in the global scope.
// Class names should be prefixed with `\`.
//
// (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
'globals_type_map' => [],
];

View File

@@ -1,12 +1,25 @@
<?php <?php
/** /**
* This configuration file was automatically generated by 'phan --init --init-level=3'
*
* TODOs (added by 'phan --init'):
*
* - Go through this file and verify that there are no missing/unnecessary files/directories.
* (E.g. this only includes direct composer dependencies
* - You may have to manually add indirect composer dependencies to 'directory_list')
* - Look at 'plugins' and add or remove plugins if appropriate
* (see https://github.com/phan/phan/tree/v5/.phan/plugins#plugins)
* - Add global suppressions for pre-existing issues to suppress_issue_types
* (https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base)
* - Consider setting up a baseline if there are a large number of pre-existing issues (see `phan --extended-help`)
*
* This configuration will be read and overlaid on top of the * This configuration will be read and overlaid on top of the
* default configuration. Command line arguments will be applied * default configuration. Command line arguments will be applied
* after this file is read. * after this file is read.
* *
* @see src/Phan/Config.php * @see https://github.com/phan/phan/wiki/Phan-Config-Settings for all configurable options
* See Config for all configurable options. * @see https://github.com/phan/phan/tree/v5/src/Phan/Config.php
* *
* A Note About Paths * A Note About Paths
* ================== * ==================
@@ -23,101 +36,343 @@
* '-d' flag. * '-d' flag.
*/ */
use Phan\Config; use Phan\Issue;
return [ return [
// "target_php_version" => "8.2",
// turn color on (-C) // The PHP version that the codebase will be checked for compatibility against.
"color_issue_messages_if_supported" => true, // For best results, the PHP binary used to run Phan should have the same PHP version.
// If true, missing properties will be created when // (Phan relies on Reflection for some types, param counts,
// and checks for undefined classes/methods/functions)
//
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`,
// `'8.0'`, `'8.1'`, `null`.
// If this is set to `null`,
// then Phan assumes the PHP version which is closest to the minor version
// of the php executable used to execute Phan.
//
// Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options)
// Automatically inferred from composer.json requirement for "php" of ">=8.2"
'target_php_version' => '8.1',
// If enabled, missing properties will be created when
// they are first seen. If false, we'll report an // they are first seen. If false, we'll report an
// error message. // error message if there is an attempt to write
"allow_missing_properties" => false, // to a class property that wasn't explicitly
// defined.
'allow_missing_properties' => false,
// Allow null to be cast as any type and for any // If enabled, null can be cast to any type and any
// type to be cast to null. // type can be cast to null. Setting this to true
"null_casts_as_any_type" => false, // will cut down on false positives.
'null_casts_as_any_type' => false,
// Backwards Compatibility Checking // If enabled, allow null to be cast as any array-like type.
'backward_compatibility_checks' => false, //
// This is an incremental step in migrating away from `null_casts_as_any_type`.
// If `null_casts_as_any_type` is true, this has no effect.
'null_casts_as_array' => true,
// Run a quick version of checks that takes less // If enabled, allow any array-like type to be cast to null.
// time // This is an incremental step in migrating away from `null_casts_as_any_type`.
"quick_mode" => false, // If `null_casts_as_any_type` is true, this has no effect.
'array_casts_as_null' => true,
// Only emit critical issues to start with // If enabled, scalars (int, float, bool, string, null)
// (0 is low severity, 5 is normal severity, 10 is critical) // are treated as if they can cast to each other.
"minimum_severity" => 0, // This does not affect checks of array keys. See `scalar_array_key_cast`.
'scalar_implicit_cast' => false,
// enable for dead code check // If enabled, any scalar array keys (int, string)
// this will spill out errors for all methods never called // are treated as if they can cast to each other.
// use after all is OK to try to find unused code blocks // E.g. `array<int,stdClass>` can cast to `array<string,stdClass>` and vice versa.
// ignore recommended: PhanUnreferencedPublicMethod // Normally, a scalar type such as int could only cast to/from int and mixed.
// "dead_code_detection" => true, 'scalar_array_key_cast' => true,
// default false for include path check // If this has entries, scalars (int, float, bool, string, null)
"enable_include_path_checks" => true, // are allowed to perform the casts listed.
"include_paths" => [ //
'.', // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]`
// '../test/configs/' // allows casting null to a string, but not vice versa.
], // (subset of `scalar_implicit_cast`)
'scalar_implicit_partial' => [],
// If enabled, Phan will warn if **any** type in a method invocation's object
// is definitely not an object,
// or if **any** type in an invoked expression is not a callable.
// Setting this to true will introduce numerous false positives
// (and reveal some bugs).
'strict_method_checking' => false,
// If enabled, Phan will warn if **any** type of the object expression for a property access
// does not contain that property.
'strict_object_checking' => false,
// If enabled, Phan will warn if **any** type in the argument's union type
// cannot be cast to a type in the parameter's expected union type.
// Setting this to true will introduce numerous false positives
// (and reveal some bugs).
'strict_param_checking' => false,
// If enabled, Phan will warn if **any** type in a property assignment's union type
// cannot be cast to a type in the property's declared union type.
// Setting this to true will introduce numerous false positives
// (and reveal some bugs).
'strict_property_checking' => false,
// If enabled, Phan will warn if **any** type in a returned value's union type
// cannot be cast to the declared return type.
// Setting this to true will introduce numerous false positives
// (and reveal some bugs).
'strict_return_checking' => false,
// If true, seemingly undeclared variables in the global
// scope will be ignored.
//
// This is useful for projects with complicated cross-file
// globals that you have no hope of fixing.
'ignore_undeclared_variables_in_global_scope' => true, 'ignore_undeclared_variables_in_global_scope' => true,
"file_list" => [ // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for,
"./test/configs/config.php", // but aren't available in the codebase, or from Reflection.
// "./test/configs/config.db.php", // (may lead to false positives if an extension isn't loaded)
// "./test/configs/config.host.php",
// "./test/configs/config.path.php",
"./test/configs/config.other.php",
"./test/configs/config.master.php",
],
// A list of directories that should be parsed for class and
// method information. After excluding the directories
// defined in exclude_analysis_directory_list, the remaining
// files will be statically analyzed for errors.
// //
// Thus, both first-party and third-party code being used by // If this is true(default), then Phan will not warn.
// your application should be included in this list. //
'directory_list' => [ // Even when this is false, Phan will still infer return values and check parameters of internal functions
// Change this to include the folders you wish to analyze // if Phan has the signatures.
// (and the folders of their dependencies) 'ignore_undeclared_functions_with_known_signatures' => true,
'src',
// To speed up analysis, we recommend going back later and
// limiting this to only the vendor/ subdirectories your
// project depends on.
// `phan --init` will generate a list of folders for you
'vendor/egrajp/smarty-extended',
],
// Backwards Compatibility Checking. This is slow
// and expensive, but you should consider running
// it before upgrading your version of PHP to a
// new version that has backward compatibility
// breaks.
//
// If you are migrating from PHP 5 to PHP 7,
// you should also look into using
// [php7cc (no longer maintained)](https://github.com/sstalle/php7cc)
// and [php7mar](https://github.com/Alexia/php7mar),
// which have different backwards compatibility checks.
//
// If you are still using versions of php older than 5.6,
// `PHP53CompatibilityPlugin` may be worth looking into if you are not running
// syntax checks for php 5.3 through another method such as
// `InvokePHPNativeSyntaxCheckPlugin` (see .phan/plugins/README.md).
'backward_compatibility_checks' => false,
// A list of directories holding code that we want // If true, check to make sure the return type declared
// to parse, but not analyze // in the doc-block (if any) matches the return type
"exclude_analysis_directory_list" => [ // declared in the method signature.
'vendor/egrajp/smarty-extended', 'check_docblock_signature_return_type_match' => false,
],
'exclude_file_list' => [
],
// what not to show as problem // This setting maps case-insensitive strings to union types.
'suppress_issue_types' => [ //
// 'PhanUndeclaredMethod', // This is useful if a project uses phpdoc that differs from the phpdoc2 standard.
'PhanEmptyFile', //
// ignore unreferences public methods, etc here (for dead code check) // If the corresponding value is the empty string,
'PhanUnreferencedPublicMethod', // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`)
'PhanUnreferencedClass', //
'PhanWriteOnlyPublicProperty', // If the corresponding value is not empty,
'PhanUnreferencedConstant', // then Phan will act as though it saw the corresponding UnionTypes(s)
'PhanWriteOnlyPublicProperty', // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc.
'PhanReadOnlyPublicProperty', //
// start ignore annotations // This matches the **entire string**, not parts of the string.
'PhanUnextractableAnnotationElementName', // (E.g. `@return the|null` will still look for a class with the name `the`,
'PhanUnextractableAnnotationSuffix', // but `@return the` will be ignored with the below setting)
], //
// (These are not aliases, this setting is ignored outside of doc comments).
// (Phan does not check if classes with these names exist)
//
// Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']`
'phpdoc_type_mapping' => [],
// Set to true in order to attempt to detect dead
// (unreferenced) code. Keep in mind that the
// results will only be a guess given that classes,
// properties, constants and methods can be referenced
// as variables (like `$class->$property` or
// `$class->$method()`) in ways that we're unable
// to make sense of.
//
// To more aggressively detect dead code,
// you may want to set `dead_code_detection_prefer_false_negative` to `false`.
'dead_code_detection' => false,
// Set to true in order to attempt to detect unused variables.
// `dead_code_detection` will also enable unused variable detection.
//
// This has a few known false positives, e.g. for loops or branches.
'unused_variable_detection' => false,
// Set to true in order to attempt to detect redundant and impossible conditions.
//
// This has some false positives involving loops,
// variables set in branches of loops, and global variables.
'redundant_condition_detection' => false,
// If enabled, Phan will act as though it's certain of real return types of a subset of internal functions,
// even if those return types aren't available in reflection
// (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version).
//
// Note that with php 7 and earlier, php would return null or false for many internal functions
// if the argument types or counts were incorrect.
// As a result, enabling this setting with target_php_version 8.0 may result in false positives
// for `--redundant-condition-detection` when codebases also support php 7.x.
'assume_real_types_for_internal_functions' => false,
// If true, this runs a quick version of checks that takes less
// time at the cost of not running as thorough
// of an analysis. You should consider setting this
// to true only when you wish you had more **undiagnosed** issues
// to fix in your code base.
//
// In quick-mode the scanner doesn't rescan a function
// or a method's code block every time a call is seen.
// This means that the problem here won't be detected:
//
// ```php
// <?php
// function test($arg):int {
// return $arg;
// }
// test("abc");
// ```
//
// This would normally generate:
//
// ```
// test.php:3 PhanTypeMismatchReturn Returning type string but test() is declared to return int
// ```
//
// The initial scan of the function's code block has no
// type information for `$arg`. It isn't until we see
// the call and rescan `test()`'s code block that we can
// detect that it is actually returning the passed in
// `string` instead of an `int` as declared.
'quick_mode' => false,
// Override to hardcode existence and types of (non-builtin) globals in the global scope. // Override to hardcode existence and types of (non-builtin) globals in the global scope.
// Class names should be prefixed with `\`. // Class names should be prefixed with `\`.
// //
// (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
'globals_type_map' => [], 'globals_type_map' => [],
// The minimum severity level to report on. This can be
// set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or
// `Issue::SEVERITY_CRITICAL`. Setting it to only
// critical issues is a good place to start on a big
// sloppy mature code base.
'minimum_severity' => Issue::SEVERITY_LOW,
// Add any issue types (such as `'PhanUndeclaredMethod'`)
// to this list to inhibit them from being reported.
'suppress_issue_types' => [
// start ignore annotations
'PhanUnextractableAnnotationElementName',
'PhanUnextractableAnnotationSuffix',
// wrongly thinks Enum is class
'PhanCommentObjectInClassConstantType',
],
// A regular expression to match files to be excluded
// from parsing and analysis and will not be read at all.
//
// This is useful for excluding groups of test or example
// directories/files, unanalyzable files, or files that
// can't be removed for whatever reason.
// (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`)
'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
// A list of files that will be excluded from parsing and analysis
// and will not be read at all.
//
// This is useful for excluding hopelessly unanalyzable
// files that can't be removed for whatever reason.
'exclude_file_list' => [],
// A directory list that defines files that will be excluded
// from static analysis, but whose class and method
// information should be included.
//
// Generally, you'll want to include the directories for
// third-party code (such as "vendor/") in this list.
//
// n.b.: If you'd like to parse but not analyze 3rd
// party code, directories containing that code
// should be added to the `directory_list` as well as
// to `exclude_analysis_directory_list`.
'exclude_analysis_directory_list' => [
'vendor/',
],
// Enable this to enable checks of require/include statements referring to valid paths.
// The settings `include_paths` and `warn_about_relative_include_statement` affect the checks.
'enable_include_path_checks' => true,
"include_paths" => [
'.',
],
// The number of processes to fork off during the analysis
// phase.
'processes' => 1,
// List of case-insensitive file extensions supported by Phan.
// (e.g. `['php', 'html', 'htm']`)
'analyzed_file_extensions' => [
'php',
],
// You can put paths to stubs of internal extensions in this config option.
// If the corresponding extension is **not** loaded, then Phan will use the stubs instead.
// Phan will continue using its detailed type annotations,
// but load the constants, classes, functions, and classes (and their Reflection types)
// from these stub files (doubling as valid php files).
// Use a different extension from php to avoid accidentally loading these.
// The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now)
//
// (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`)
'autoload_internal_extension_signatures' => [],
// A list of plugin files to execute.
//
// Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`)
//
// Documentation about available bundled plugins can be found
// [here](https://github.com/phan/phan/tree/v5/.phan/plugins).
//
// Alternately, you can pass in the full path to a PHP file with the plugin's implementation
// (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`)
'plugins' => [
'AlwaysReturnPlugin',
'PregRegexCheckerPlugin',
'UnreachableCodePlugin',
],
// A list of directories that should be parsed for class and
// method information. After excluding the directories
// defined in `exclude_analysis_directory_list`, the remaining
// files will be statically analyzed for errors.
//
// Thus, both first-party and third-party code being used by
// your application should be included in this list.
'directory_list' => [
'src',
'vendor/egrajp/smarty-extended/src',
'vendor/phan/phan/src/Phan',
'vendor/phpunit/phpunit/src',
'vendor/psr/log/src',
'vendor/vimeo/psalm/src/Psalm',
'vendor/gullevek/dotenv',
],
// A list of individual files to include in analysis
// with a path relative to the root directory of the
// project.
'file_list' => [
"./test/configs/config.php",
"./test/configs/config.other.php",
"./test/configs/config.master.php",
],
]; ];

View File

@@ -16,7 +16,7 @@
], ],
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"php": ">=8.1", "php": ">=8.2",
"psr/log": "^3.0@dev" "psr/log": "^3.0@dev"
}, },
"require-dev": { "require-dev": {
@@ -24,7 +24,8 @@
"phan/phan": "v5.x-dev", "phan/phan": "v5.x-dev",
"phpunit/phpunit": "^9", "phpunit/phpunit": "^9",
"egrajp/smarty-extended": "^4.3", "egrajp/smarty-extended": "^4.3",
"vimeo/psalm": "^5.0@dev" "vimeo/psalm": "^5.0@dev",
"gullevek/dotenv": "dev-master"
}, },
"repositories": { "repositories": {
"git.egplusww.jp.Composer": { "git.egplusww.jp.Composer": {

1
publish/.gitignore vendored
View File

@@ -1,2 +1 @@
*.zip
.env* .env*

View File

@@ -1 +1 @@
9.3.0 9.6.2

1
publish/package-download/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.zip

View File

@@ -1,6 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BASE_FOLDER=$(dirname $(readlink -f $0))"/"; BASE_FOLDER=$(dirname $(readlink -f $0))"/";
PACKAGE_DOWNLOAD="${BASE_FOLDER}package-download/";
if [ ! -d "${PACKAGE_DOWNLOAD}" ]; then
mkdir "${PACKAGE_DOWNLOAD}";
fi;
VERSION=$(git tag --list | sort -V | tail -n1 | sed -e "s/^v//"); VERSION=$(git tag --list | sort -V | tail -n1 | sed -e "s/^v//");
file_last_published="${BASE_FOLDER}last.published"; file_last_published="${BASE_FOLDER}last.published";
go_flag="$1"; go_flag="$1";
@@ -19,6 +23,7 @@ if [ -f "${file_last_published}" ]; then
fi; fi;
# read in the .env.deploy file and we must have # read in the .env.deploy file and we must have
# GITEA_UPLOAD_FILENAME
# GITLAB_USER # GITLAB_USER
# GITLAB_TOKEN # GITLAB_TOKEN
# GITLAB_URL # GITLAB_URL
@@ -45,17 +50,18 @@ fi;
echo "[START]"; echo "[START]";
# gitea # gitea
if [ ! -z "${GITEA_URL_DL}" ] && [ ! -z "${GITEA_URL_PUSH}" ] && if [ ! -z "${GITEA_UPLOAD_FILENAME}" ] &&
[ ! -z "${GITEA_URL_DL}" ] && [ ! -z "${GITEA_URL_PUSH}" ] &&
[ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then [ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
curl -LJO \ curl -LJO \
--output-dir "${BASE_FOLDER}" \ --output-dir "${PACKAGE_DOWNLOAD}" \
${GITEA_URL_DL}/v${VERSION}.zip; ${GITEA_URL_DL}/v${VERSION}.zip;
curl --user ${GITEA_USER}:${GITEA_TOKEN} \ curl --user ${GITEA_USER}:${GITEA_TOKEN} \
--upload-file "${BASE_FOLDER}/CoreLibs-Composer-All-v${VERSION}.zip" \ --upload-file "${PACKAGE_DOWNLOAD}${GITEA_UPLOAD_FILENAME}-v${VERSION}.zip" \
${GITEA_URL_PUSH}?version=${VERSION}; ${GITEA_URL_PUSH}?version=${VERSION};
echo "${VERSION}" > "${file_last_published}"; echo "${VERSION}" > "${file_last_published}";
else else
echo "Missing either GITEA_USER or GITEA_TOKEN environment variable"; echo "Missing either GITEA_UPLOAD_FILENAME, GITEA_URL_DL, GITEA_URL_PUSH, GITEA_USER or GITEA_TOKEN environment variable";
fi; fi;
# gitlab # gitlab

View File

@@ -231,8 +231,6 @@ class Login
) { ) {
// attach db class // attach db class
$this->db = $db; $this->db = $db;
// log login data for this class only
$log->setLogFlag(\CoreLibs\Logging\Logger\Flag::per_class);
// attach logger // attach logger
$this->log = $log; $this->log = $log;
// attach session class // attach session class
@@ -242,7 +240,7 @@ class Login
if (false === $this->loginSetOptions($options)) { if (false === $this->loginSetOptions($options)) {
// on failure, exit // on failure, exit
echo "<b>Could not set options</b>"; echo "<b>Could not set options</b>";
$this->loginTerminate(4000); $this->loginTerminate('Could not set options', 3000);
} }
// string key, msg: string, flag: e (error), o (ok) // string key, msg: string, flag: e (error), o (ok)
@@ -394,11 +392,18 @@ class Login
/** /**
* Wrapper for exit calls * Wrapper for exit calls
* *
* @param int $code * @param string $message [='']
* @param int $code [=0]
* @return void * @return void
*/ */
protected function loginTerminate($code = 0): void protected function loginTerminate(string $message = '', int $code = 0): void
{ {
// all below 1000 are info end, all above 1000 are critical -> should throw exception?
if ($code < 1000) {
$this->log->info($message, ['code' => $code]);
} else {
$this->log->critical($message, ['code' => $code]);
}
exit($code); exit($code);
} }
@@ -1060,9 +1065,9 @@ class Login
]; ];
// set the default unit // set the default unit
if ($res['edit_default']) { if ($res['edit_default']) {
$_SESSION['UNIT_DEFAULT'] = $res['edit_access_id']; $_SESSION['UNIT_DEFAULT'] = (int)$res['edit_access_id'];
} }
$_SESSION['UNIT_UID'][$res['uid']] = $res['edit_access_id']; $_SESSION['UNIT_UID'][$res['uid']] = (int)$res['edit_access_id'];
// sub arrays for simple access // sub arrays for simple access
array_push($eauid, $res['edit_access_id']); array_push($eauid, $res['edit_access_id']);
$unit_acl[$res['edit_access_id']] = $res['level']; $unit_acl[$res['edit_access_id']] = $res['level'];
@@ -1148,18 +1153,18 @@ class Login
// user > page > group // user > page > group
// group ACL 0 // group ACL 0
if ($_SESSION['GROUP_ACL_LEVEL'] != -1) { if ($_SESSION['GROUP_ACL_LEVEL'] != -1) {
$this->acl['base'] = $_SESSION['GROUP_ACL_LEVEL']; $this->acl['base'] = (int)$_SESSION['GROUP_ACL_LEVEL'];
} }
// page ACL 1 // page ACL 1
if ( if (
isset($_SESSION['PAGES_ACL_LEVEL'][$this->page_name]) && isset($_SESSION['PAGES_ACL_LEVEL'][$this->page_name]) &&
$_SESSION['PAGES_ACL_LEVEL'][$this->page_name] != -1 $_SESSION['PAGES_ACL_LEVEL'][$this->page_name] != -1
) { ) {
$this->acl['base'] = $_SESSION['PAGES_ACL_LEVEL'][$this->page_name]; $this->acl['base'] = (int)$_SESSION['PAGES_ACL_LEVEL'][$this->page_name];
} }
// user ACL 2 // user ACL 2
if ($_SESSION['USER_ACL_LEVEL'] != -1) { if ($_SESSION['USER_ACL_LEVEL'] != -1) {
$this->acl['base'] = $_SESSION['USER_ACL_LEVEL']; $this->acl['base'] = (int)$_SESSION['USER_ACL_LEVEL'];
} }
} }
$_SESSION['BASE_ACL_LEVEL'] = $this->acl['base']; $_SESSION['BASE_ACL_LEVEL'] = $this->acl['base'];
@@ -1812,14 +1817,14 @@ HTML;
$this->login_error = 1; $this->login_error = 1;
echo 'Could not connect to DB<br>'; echo 'Could not connect to DB<br>';
// if I can't connect to the DB to auth exit hard. No access allowed // if I can't connect to the DB to auth exit hard. No access allowed
$this->loginTerminate(1000); $this->loginTerminate('Could not connect to DB', 1000);
} }
// initial the session if there is no session running already // initial the session if there is no session running already
// check if session exists and could be created // check if session exists and could be created
if ($this->session->checkActiveSession() === false) { if ($this->session->checkActiveSession() === false) {
$this->login_error = 2; $this->login_error = 2;
echo '<b>No active session found</b>'; echo '<b>No active session found</b>';
$this->loginTerminate(2000); $this->loginTerminate('No active session found', 2000);
} }
// set internal page name // set internal page name
$this->page_name = $this->loginReadPageName(); $this->page_name = $this->loginReadPageName();
@@ -1918,7 +1923,7 @@ HTML;
$this->loginPrintLogin(); $this->loginPrintLogin();
} }
// exit so we don't process anything further, at all // exit so we don't process anything further, at all
$this->loginTerminate(3000); $this->loginTerminate('Exit after non ajax page load', 100);
} else { } else {
// if we are on an ajax page reset any POST/GET array data to avoid // if we are on an ajax page reset any POST/GET array data to avoid
// any accidentical processing going on // any accidentical processing going on
@@ -1926,7 +1931,7 @@ HTML;
$_GET = []; $_GET = [];
// set the action to login so we can trigger special login html return // set the action to login so we can trigger special login html return
$_POST['action'] = 'login'; $_POST['action'] = 'login';
$_POST['login_exit'] = 3000; $_POST['login_exit'] = 100;
$_POST['login_error'] = $this->loginGetLastErrorCode(); $_POST['login_error'] = $this->loginGetLastErrorCode();
$_POST['login_error_text'] = $this->loginGetErrorMsg( $_POST['login_error_text'] = $this->loginGetErrorMsg(
$this->loginGetLastErrorCode(), $this->loginGetLastErrorCode(),
@@ -2347,7 +2352,10 @@ HTML;
is_array($_SESSION['UNIT']) && is_array($_SESSION['UNIT']) &&
!array_key_exists($edit_access_id, $_SESSION['UNIT']) !array_key_exists($edit_access_id, $_SESSION['UNIT'])
) { ) {
return $_SESSION['UNIT_DEFAULT'] ?? null; $edit_access_id = null;
if (is_numeric($_SESSION['UNIT_DEFAULT'])) {
$edit_access_id = (int)$_SESSION['UNIT_DEFAULT'];
}
} }
return $edit_access_id; return $edit_access_id;
} }

View File

@@ -164,6 +164,10 @@ class Backend
); );
} }
$this->default_acl = $set_default_acl_level ?? DEFAULT_ACL_LEVEL; $this->default_acl = $set_default_acl_level ?? DEFAULT_ACL_LEVEL;
// if negative or larger than 100, reset to 0
if ($this->default_acl < 0 || $this->default_acl > 100) {
$this->default_acl = 0;
}
// queue key // queue key
if (preg_match("/^(add|save|delete|remove|move|up|down|push_live)$/", $this->action)) { if (preg_match("/^(add|save|delete|remove|move|up|down|push_live)$/", $this->action)) {
@@ -552,7 +556,7 @@ class Backend
string $suffix = '', string $suffix = '',
int $min_steps = 1, int $min_steps = 1,
bool $name_pos_back = false bool $name_pos_back = false
) { ): string {
// get the build layout // get the build layout
$html_time = \CoreLibs\Output\Form\Elements::printDateTime( $html_time = \CoreLibs\Output\Form\Elements::printDateTime(
$year, $year,

View File

@@ -14,8 +14,6 @@ declare(strict_types=1);
namespace CoreLibs\Check; namespace CoreLibs\Check;
use Exception;
class Colors class Colors
{ {
/** @var int 1 for HEX rgb */ /** @var int 1 for HEX rgb */
@@ -41,6 +39,7 @@ class Colors
* @param int|false $rgb_flag flag to check for rgb * @param int|false $rgb_flag flag to check for rgb
* @param int|false $hsl_flag flag to check for hsl type * @param int|false $hsl_flag flag to check for hsl type
* @return bool True if no error, False if error * @return bool True if no error, False if error
* @throws \UnexpectedValueException 1: cannot extract color from string
*/ */
private static function rgbHslContentCheck( private static function rgbHslContentCheck(
string $color, string $color,
@@ -52,7 +51,7 @@ class Colors
if ( if (
!is_array($color_list = preg_split("/,\s*/", $matches[1] ?? '')) !is_array($color_list = preg_split("/,\s*/", $matches[1] ?? ''))
) { ) {
throw new \Exception("Could not extract color list from rgg/hsl", 3); throw new \UnexpectedValueException("Could not extract color list from rgg/hsl", 1);
} }
// based on rgb/hsl settings check that entries are valid // based on rgb/hsl settings check that entries are valid
// rgb: either 0-255 OR 0-100% // rgb: either 0-255 OR 0-100%
@@ -124,7 +123,8 @@ class Colors
* @param int $flags defaults to ALL, else use | to combined from * @param int $flags defaults to ALL, else use | to combined from
* HEX_RGB, HEX_RGBA, RGB, RGBA, HSL, HSLA * HEX_RGB, HEX_RGBA, RGB, RGBA, HSL, HSLA
* @return bool True if valid, False if not * @return bool True if valid, False if not
* @throws Exception 1: no valid flag set * @throws \UnexpectedValueException 1: no valid flag set
* @throws \InvalidArgumentException 2: no regex block set
*/ */
public static function validateColor(string $color, int $flags = self::ALL): bool public static function validateColor(string $color, int $flags = self::ALL): bool
{ {
@@ -152,10 +152,10 @@ class Colors
} }
// wrong flag set // wrong flag set
if ($flags > self::ALL) { if ($flags > self::ALL) {
throw new \Exception("Invalid flags parameter: $flags", 1); throw new \UnexpectedValueException("Invalid flags parameter: $flags", 1);
} }
if (!count($regex_blocks)) { if (!count($regex_blocks)) {
throw new \Exception("No regex blocks set: $flags", 2); throw new \InvalidArgumentException("No regex blocks set: $flags", 2);
} }
// build regex // build regex

View File

@@ -169,10 +169,10 @@ class Email
* @param string $email email string * @param string $email email string
* @param bool $short default false, if true, * @param bool $short default false, if true,
* returns only short type (pc instead of pc_html) * returns only short type (pc instead of pc_html)
* @return string|bool email type, eg "pc", "docomo", etc, * @return string|false email type, eg "pc", "docomo", etc,
* false for invalid short type * false for invalid short type
*/ */
public static function getEmailType(string $email, bool $short = false) public static function getEmailType(string $email, bool $short = false): string|false
{ {
// trip if there is no email address // trip if there is no email address
if (!$email) { if (!$email) {
@@ -200,9 +200,9 @@ class Email
* gets the short email type from a long email type * gets the short email type from a long email type
* *
* @param string $email_type email string * @param string $email_type email string
* @return string|bool short string or false for invalid * @return string|false short string or false for invalid
*/ */
public static function getShortEmailType(string $email_type) public static function getShortEmailType(string $email_type): string|false
{ {
// check if the short email type exists // check if the short email type exists
if (isset(self::$mobile_email_type_short[$email_type])) { if (isset(self::$mobile_email_type_short[$email_type])) {

View File

@@ -90,27 +90,26 @@ class Encoding
$temp = mb_convert_encoding($string, $to_encoding, $from_encoding); $temp = mb_convert_encoding($string, $to_encoding, $from_encoding);
$compare = mb_convert_encoding($temp, $from_encoding, $to_encoding); $compare = mb_convert_encoding($temp, $from_encoding, $to_encoding);
// if string does not match anymore we have a convert problem // if string does not match anymore we have a convert problem
if ($string != $compare) { if ($string == $compare) {
$failed = [];
// go through each character and find the ones that do not match
for ($i = 0, $iMax = mb_strlen($string, $from_encoding); $i < $iMax; $i++) {
$char = mb_substr($string, $i, 1, $from_encoding);
$r_char = mb_substr($compare, $i, 1, $from_encoding);
// the ord 194 is a hack to fix the IE7/IE8
// bug with line break and illegal character
if (
(($char != $r_char && (!self::$mb_error_char ||
in_array(self::$mb_error_char, ['none', 'long', 'entity']))) ||
($char != $r_char && $r_char == self::$mb_error_char && self::$mb_error_char)) &&
ord($char) != 194
) {
$failed[] = $char;
}
}
return $failed;
} else {
return false; return false;
} }
$failed = [];
// go through each character and find the ones that do not match
for ($i = 0, $iMax = mb_strlen($string, $from_encoding); $i < $iMax; $i++) {
$char = mb_substr($string, $i, 1, $from_encoding);
$r_char = mb_substr($compare, $i, 1, $from_encoding);
// the ord 194 is a hack to fix the IE7/IE8
// bug with line break and illegal character
if (
(($char != $r_char && (!self::$mb_error_char ||
in_array(self::$mb_error_char, ['none', 'long', 'entity']))) ||
($char != $r_char && $r_char == self::$mb_error_char && self::$mb_error_char)) &&
ord($char) != 194
) {
$failed[] = $char;
}
}
return $failed;
} }
} }

View File

@@ -245,14 +245,13 @@ class ArrayHandler
* bool key flag: true: handle keys as string or int * bool key flag: true: handle keys as string or int
* default false: all keys are string * default false: all keys are string
* *
* @return array<mixed>|false merged array * @return array<mixed> merged array
*/ */
public static function arrayMergeRecursive(): array|false public static function arrayMergeRecursive(): array
{ {
// croak on not enough arguemnts (we need at least two) // croak on not enough arguemnts (we need at least two)
if (func_num_args() < 2) { if (func_num_args() < 2) {
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING); throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
return false;
} }
// default key is not string // default key is not string
$key_is_string = false; $key_is_string = false;
@@ -265,15 +264,13 @@ class ArrayHandler
} }
// check that arrays count is at least two, else we don't have enough to do anything // check that arrays count is at least two, else we don't have enough to do anything
if (count($arrays) < 2) { if (count($arrays) < 2) {
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING); throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
return false;
} }
$merged = []; $merged = [];
while ($arrays) { while ($arrays) {
$array = array_shift($arrays); $array = array_shift($arrays);
if (!is_array($array)) { if (!is_array($array)) {
trigger_error(__FUNCTION__ . ' encountered a non array argument', E_USER_WARNING); throw new \TypeError(__FUNCTION__ . ' encountered a non array argument');
return false;
} }
if (!$array) { if (!$array) {
continue; continue;

View File

@@ -105,49 +105,48 @@ class DateTime
bool $show_micro = true bool $show_micro = true
): string { ): string {
// check if the timestamp has any h/m/s/ms inside, if yes skip // check if the timestamp has any h/m/s/ms inside, if yes skip
if (!preg_match("/(h|m|s|ms)/", (string)$timestamp)) { if (preg_match("/(h|m|s|ms)/", (string)$timestamp)) {
list($timestamp, $ms) = array_pad(explode('.', (string)round((float)$timestamp, 4)), 2, null); return (string)$timestamp;
// if negative remember }
$negative = false; list($timestamp, $ms) = array_pad(explode('.', (string)round((float)$timestamp, 4)), 2, null);
if ((int)$timestamp < 0) { // if negative remember
$negative = true; $negative = false;
} if ((int)$timestamp < 0) {
$timestamp = abs((float)$timestamp); $negative = true;
$timegroups = [86400, 3600, 60, 1]; }
$labels = ['d', 'h', 'm', 's']; $timestamp = abs((float)$timestamp);
$time_string = ''; $timegroups = [86400, 3600, 60, 1];
// if timestamp is zero, return zero string $labels = ['d', 'h', 'm', 's'];
if ($timestamp == 0) { $time_string = '';
$time_string = '0s'; // if timestamp is zero, return zero string
} else { if ($timestamp == 0) {
for ($i = 0, $iMax = count($timegroups); $i < $iMax; $i++) { $time_string = '0s';
$output = floor((float)$timestamp / $timegroups[$i]);
$timestamp = (float)$timestamp % $timegroups[$i];
// output has days|hours|min|sec
if ($output || $time_string) {
$time_string .= $output . $labels[$i] . (($i + 1) != count($timegroups) ? ' ' : '');
}
}
}
// only add ms if we have an ms value
if ($ms !== null) {
// if we have ms and it has leading zeros, remove them, but only if it is nut just 0
$ms = preg_replace("/^0+(\d+)$/", '${1}', $ms);
if (!is_string($ms) || empty($ms)) {
$ms = '0';
}
// add ms if there
if ($show_micro) {
$time_string .= ' ' . $ms . 'ms';
} elseif (!$time_string) {
$time_string .= $ms . 'ms';
}
}
if ($negative) {
$time_string = '-' . $time_string;
}
} else { } else {
$time_string = $timestamp; for ($i = 0, $iMax = count($timegroups); $i < $iMax; $i++) {
$output = floor((float)$timestamp / $timegroups[$i]);
$timestamp = (float)$timestamp % $timegroups[$i];
// output has days|hours|min|sec
if ($output || $time_string) {
$time_string .= $output . $labels[$i] . (($i + 1) != count($timegroups) ? ' ' : '');
}
}
}
// only add ms if we have an ms value
if ($ms !== null) {
// if we have ms and it has leading zeros, remove them, but only if it is nut just 0
$ms = preg_replace("/^0+(\d+)$/", '${1}', $ms);
if (!is_string($ms) || empty($ms)) {
$ms = '0';
}
// add ms if there
if ($show_micro) {
$time_string .= ' ' . $ms . 'ms';
} elseif (!$time_string) {
$time_string .= $ms . 'ms';
}
}
if ($negative) {
$time_string = '-' . $time_string;
} }
return (string)$time_string; return (string)$time_string;
} }
@@ -162,37 +161,36 @@ class DateTime
public static function stringToTime(string|int|float $timestring): string|int|float public static function stringToTime(string|int|float $timestring): string|int|float
{ {
$timestamp = 0; $timestamp = 0;
if (preg_match("/(d|h|m|s|ms)/", (string)$timestring)) { if (!preg_match("/(d|h|m|s|ms)/", (string)$timestring)) {
$timestring = (string)$timestring;
// pos for preg match read + multiply factor
$timegroups = [2 => 86400, 4 => 3600, 6 => 60, 8 => 1];
$matches = [];
// if start with -, strip and set negative
$negative = false;
if (preg_match("/^-/", $timestring)) {
$negative = true;
$timestring = substr($timestring, 1);
}
// preg match: 0: full string
// 2, 4, 6, 8 are the to need values
preg_match("/^((\d+)d ?)?((\d+)h ?)?((\d+)m ?)?((\d+)s ?)?((\d+)ms)?$/", $timestring, $matches);
// multiply the returned matches and sum them up. the last one (ms) is added with .
foreach ($timegroups as $i => $time_multiply) {
if (isset($matches[$i]) && is_numeric($matches[$i])) {
$timestamp += (float)$matches[$i] * $time_multiply;
}
}
if (isset($matches[10]) && is_numeric($matches[10])) {
$timestamp .= '.' . $matches[10];
}
if ($negative) {
// cast to flaot so we can do a negative multiplication
$timestamp = (float)$timestamp * -1;
}
return $timestamp;
} else {
return $timestring; return $timestring;
} }
$timestring = (string)$timestring;
// pos for preg match read + multiply factor
$timegroups = [2 => 86400, 4 => 3600, 6 => 60, 8 => 1];
$matches = [];
// if start with -, strip and set negative
$negative = false;
if (preg_match("/^-/", $timestring)) {
$negative = true;
$timestring = substr($timestring, 1);
}
// preg match: 0: full string
// 2, 4, 6, 8 are the to need values
preg_match("/^((\d+)d ?)?((\d+)h ?)?((\d+)m ?)?((\d+)s ?)?((\d+)ms)?$/", $timestring, $matches);
// multiply the returned matches and sum them up. the last one (ms) is added with .
foreach ($timegroups as $i => $time_multiply) {
if (isset($matches[$i]) && is_numeric($matches[$i])) {
$timestamp += (float)$matches[$i] * $time_multiply;
}
}
if (isset($matches[10]) && is_numeric($matches[10])) {
$timestamp .= '.' . $matches[10];
}
if ($negative) {
// cast to flaot so we can do a negative multiplication
$timestamp = (float)$timestamp * -1;
}
return $timestamp;
} }
/** /**
@@ -323,36 +321,36 @@ class DateTime
* *
* @param string $start_date start date string in YYYY-MM-DD * @param string $start_date start date string in YYYY-MM-DD
* @param string $end_date end date string in YYYY-MM-DD * @param string $end_date end date string in YYYY-MM-DD
* @return int|bool false on error * @return int int -1 (s<e)/0 (s=e)/1 (s>e) as difference
* or int -1 (s<e)/0 (s=e)/1 (s>e) as difference * @throws \UnexpectedValueException On empty start/end values
*/ */
public static function compareDate(string $start_date, string $end_date): int|bool public static function compareDate(string $start_date, string $end_date): int
{ {
// pre check for empty or wrong // pre check for empty or wrong
if ($start_date == '--' || $end_date == '--' || !$start_date || !$end_date) { if ($start_date == '--' || $end_date == '--' || empty($start_date) || empty($end_date)) {
return false; throw new \UnexpectedValueException('Start or End date not set or are just "--"', 1);
} }
// if invalid, quit // if invalid, quit
if (($start_timestamp = strtotime($start_date)) === false) { if (($start_timestamp = strtotime($start_date)) === false) {
return false; throw new \UnexpectedValueException("Error parsing start date through strtotime()", 2);
} }
if (($end_timestamp = strtotime($end_date)) === false) { if (($end_timestamp = strtotime($end_date)) === false) {
return false; throw new \UnexpectedValueException("Error parsing end date through strtotime()", 3);
} }
$comp = 0;
// convert anything to Y-m-d and then to timestamp // convert anything to Y-m-d and then to timestamp
// this is to remove any time parts // this is to remove any time parts
$start_timestamp = strtotime(date('Y-m-d', $start_timestamp)); $start_timestamp = strtotime(date('Y-m-d', $start_timestamp));
$end_timestamp = strtotime(date('Y-m-d', $end_timestamp)); $end_timestamp = strtotime(date('Y-m-d', $end_timestamp));
// compare, or end with false // compare, or end with false
if ($start_timestamp < $end_timestamp) { if ($start_timestamp < $end_timestamp) {
return -1; $comp = -1;
} elseif ($start_timestamp == $end_timestamp) { } elseif ($start_timestamp == $end_timestamp) {
return 0; $comp = 0;
} elseif ($start_timestamp > $end_timestamp) { } elseif ($start_timestamp > $end_timestamp) {
return 1; $comp = 1;
} else {
return false;
} }
return $comp;
} }
/** /**
@@ -366,32 +364,32 @@ class DateTime
* *
* @param string $start_datetime start date/time in YYYY-MM-DD HH:mm:ss * @param string $start_datetime start date/time in YYYY-MM-DD HH:mm:ss
* @param string $end_datetime end date/time in YYYY-MM-DD HH:mm:ss * @param string $end_datetime end date/time in YYYY-MM-DD HH:mm:ss
* @return int|bool false for error * @return int -1 (s<e)/0 (s=e)/1 (s>e) as difference
* or -1 (s<e)/0 (s=e)/1 (s>e) as difference * @throws \UnexpectedValueException On empty start/end values
*/ */
public static function compareDateTime(string $start_datetime, string $end_datetime): int|bool public static function compareDateTime(string $start_datetime, string $end_datetime): int
{ {
// pre check for empty or wrong // pre check for empty or wrong
if ($start_datetime == '--' || $end_datetime == '--' || !$start_datetime || !$end_datetime) { if ($start_datetime == '--' || $end_datetime == '--' || empty($start_datetime) || empty($end_datetime)) {
return false; throw new \UnexpectedValueException('Start or end timestamp not set or are just "--"', 1);
} }
// quit if invalid timestamp // quit if invalid timestamp
if (($start_timestamp = strtotime($start_datetime)) === false) { if (($start_timestamp = strtotime($start_datetime)) === false) {
return false; throw new \UnexpectedValueException("Error parsing start timestamp through strtotime()", 2);
} }
if (($end_timestamp = strtotime($end_datetime)) === false) { if (($end_timestamp = strtotime($end_datetime)) === false) {
return false; throw new \UnexpectedValueException("Error parsing end timestamp through strtotime()", 3);
} }
$comp = 0;
// compare, or return false // compare, or return false
if ($start_timestamp < $end_timestamp) { if ($start_timestamp < $end_timestamp) {
return -1; $comp = -1;
} elseif ($start_timestamp == $end_timestamp) { } elseif ($start_timestamp == $end_timestamp) {
return 0; $comp = 0;
} elseif ($start_timestamp > $end_timestamp) { } elseif ($start_timestamp > $end_timestamp) {
return 1; $comp = 1;
} else {
return false;
} }
return $comp;
} }
/** /**

View File

@@ -28,15 +28,15 @@ class Colors
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @param bool $hex_prefix default true, prefix with "#" * @param bool $hex_prefix default true, prefix with "#"
* @return string|bool rgb in hex values with leading # if set, * @return string rgb in hex values with leading # if set,
* false for invalid color * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hex( public static function rgb2hex(
int $red, int $red,
int $green, int $green,
int $blue, int $blue,
bool $hex_prefix = true bool $hex_prefix = true
): string|bool { ): string {
$hex_color = ''; $hex_color = '';
if ($hex_prefix === true) { if ($hex_prefix === true) {
$hex_color = '#'; $hex_color = '#';
@@ -44,7 +44,8 @@ class Colors
foreach (['red', 'green', 'blue'] as $color) { foreach (['red', 'green', 'blue'] as $color) {
// if not valid, abort // if not valid, abort
if ($$color < 0 || $$color > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
} }
// pad left with 0 // pad left with 0
$hex_color .= str_pad(dechex($$color), 2, '0', STR_PAD_LEFT); $hex_color .= str_pad(dechex($$color), 2, '0', STR_PAD_LEFT);
@@ -55,37 +56,39 @@ class Colors
/** /**
* converts a hex RGB color to the int numbers * converts a hex RGB color to the int numbers
* *
* @param string $hexStr RGB hexstring * @param string $hex_string RGB hexstring
* @param bool $return_as_string flag to return as string * @param bool $return_as_string flag to return as string
* @param string $seperator string seperator: default: "," * @param string $seperator string seperator: default: ","
* @return string|array<string,float|int>|bool false on error or array with RGB * @return string|array<string,float|int> array with RGB
* or a string with the seperator * or a string with the seperator
* @throws \InvalidArgumentException if hex string is empty
* @throws \UnexpectedValueException if the hex string value is not valid
*/ */
public static function hex2rgb( public static function hex2rgb(
string $hexStr, string $hex_string,
bool $return_as_string = false, bool $return_as_string = false,
string $seperator = ',' string $seperator = ','
): string|array|bool { ): string|array {
$hexStr = preg_replace("/[^0-9A-Fa-f]/", '', $hexStr); // Gets a proper hex string $hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $hex_string); // Gets a proper hex string
if (!is_string($hexStr)) { if (!is_string($hex_string)) {
return false; throw new \InvalidArgumentException('hex_string argument cannot be empty', 1);
} }
$rgbArray = []; $rgbArray = [];
if (strlen($hexStr) == 6) { if (strlen($hex_string) == 6) {
// If a proper hex code, convert using bitwise operation. // If a proper hex code, convert using bitwise operation.
// No overhead... faster // No overhead... faster
$colorVal = hexdec($hexStr); $colorVal = hexdec($hex_string);
$rgbArray['r'] = 0xFF & ($colorVal >> 0x10); $rgbArray['r'] = 0xFF & ($colorVal >> 0x10);
$rgbArray['g'] = 0xFF & ($colorVal >> 0x8); $rgbArray['g'] = 0xFF & ($colorVal >> 0x8);
$rgbArray['b'] = 0xFF & $colorVal; $rgbArray['b'] = 0xFF & $colorVal;
} elseif (strlen($hexStr) == 3) { } elseif (strlen($hex_string) == 3) {
// If shorthand notation, need some string manipulations // If shorthand notation, need some string manipulations
$rgbArray['r'] = hexdec(str_repeat(substr($hexStr, 0, 1), 2)); $rgbArray['r'] = hexdec(str_repeat(substr($hex_string, 0, 1), 2));
$rgbArray['g'] = hexdec(str_repeat(substr($hexStr, 1, 1), 2)); $rgbArray['g'] = hexdec(str_repeat(substr($hex_string, 1, 1), 2));
$rgbArray['b'] = hexdec(str_repeat(substr($hexStr, 2, 1), 2)); $rgbArray['b'] = hexdec(str_repeat(substr($hex_string, 2, 1), 2));
} else { } else {
// Invalid hex color code // Invalid hex color code
return false; throw new \UnexpectedValueException('Invalid hex_string: ' . $hex_string, 2);
} }
// returns the rgb string or the associative array // returns the rgb string or the associative array
return $return_as_string ? implode($seperator, $rgbArray) : $rgbArray; return $return_as_string ? implode($seperator, $rgbArray) : $rgbArray;
@@ -97,20 +100,21 @@ class Colors
* returns: * returns:
* array with hue (0-360), sat (0-100%), brightness/value (0-100%) * array with hue (0-360), sat (0-100%), brightness/value (0-100%)
* *
* @param int $red red 0-255 * @param int $red red 0-255
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @return array<int|float>|bool Hue, Sat, Brightness/Value * @return array<int|float> Hue, Sat, Brightness/Value
* false for input value error * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hsb(int $red, int $green, int $blue): array|bool public static function rgb2hsb(int $red, int $green, int $blue): array
{ {
// check that rgb is from 0 to 255 // check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) { foreach (['red', 'green', 'blue'] as $color) {
if ($$c < 0 || $$c > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
} }
$$c = $$c / 255; $$color = $$color / 255;
} }
$MAX = max($red, $green, $blue); $MAX = max($red, $green, $blue);
@@ -144,13 +148,13 @@ class Colors
* converts HSB/V to RGB values RGB is full INT * converts HSB/V to RGB values RGB is full INT
* if HSB/V value is invalid, sets this value to 0 * if HSB/V value is invalid, sets this value to 0
* *
* @param float $H hue 0-360 (int) * @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int) * @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int) * @param float $V brightness/value 0-100 (int)
* @return array<int>|bool 0 red/1 green/2 blue array as 0-255 * @return array<int> 0 red/1 green/2 blue array as 0-255
* false for input value error * @throws \LengthException If any argument is not in the valid range
*/ */
public static function hsb2rgb(float $H, float $S, float $V): array|bool public static function hsb2rgb(float $H, float $S, float $V): array
{ {
// check that H is 0 to 359, 360 = 0 // check that H is 0 to 359, 360 = 0
// and S and V are 0 to 1 // and S and V are 0 to 1
@@ -158,13 +162,13 @@ class Colors
$H = 0; $H = 0;
} }
if ($H < 0 || $H > 359) { if ($H < 0 || $H > 359) {
return false; throw new \LengthException('Argument value ' . $H . ' for hue is not in the range of 0 to 359', 1);
} }
if ($S < 0 || $S > 100) { if ($S < 0 || $S > 100) {
return false; throw new \LengthException('Argument value ' . $S . ' for saturation is not in the range of 0 to 100', 2);
} }
if ($V < 0 || $V > 100) { if ($V < 0 || $V > 100) {
return false; throw new \LengthException('Argument value ' . $V . ' for brightness is not in the range of 0 to 100', 3);
} }
// convert to internal 0-1 format // convert to internal 0-1 format
$S /= 100; $S /= 100;
@@ -230,20 +234,21 @@ class Colors
* return: * return:
* array with hue (0-360), saturation (0-100%) and luminance (0-100%) * array with hue (0-360), saturation (0-100%) and luminance (0-100%)
* *
* @param int $red red 0-255 * @param int $red red 0-255
* @param int $green green 0-255 * @param int $green green 0-255
* @param int $blue blue 0-255 * @param int $blue blue 0-255
* @return array<float>|bool hue/sat/luminance * @return array<float> hue/sat/luminance
* false for input value error * @throws \LengthException If any argument is not in the range of 0~255
*/ */
public static function rgb2hsl(int $red, int $green, int $blue): array|bool public static function rgb2hsl(int $red, int $green, int $blue): array
{ {
// check that rgb is from 0 to 255 // check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) { foreach (['red', 'green', 'blue'] as $color) {
if ($$c < 0 || $$c > 255) { if ($$color < 0 || $$color > 255) {
return false; throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
} }
$$c = $$c / 255; $$color = $$color / 255;
} }
$min = min($red, $green, $blue); $min = min($red, $green, $blue);
@@ -284,24 +289,25 @@ class Colors
* converts an HSL to RGB * converts an HSL to RGB
* if HSL value is invalid, set this value to 0 * if HSL value is invalid, set this value to 0
* *
* @param float $hue hue: 0-360 (degrees) * @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100 * @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100 * @param float $lum luminance: 0-100
* @return array<int,float|int>|bool red/blue/green 0-255 each * @return array<int,float|int> red/blue/green 0-255 each
* @throws \LengthException If any argument is not in the valid range
*/ */
public static function hsl2rgb(float $hue, float $sat, float $lum): array|bool public static function hsl2rgb(float $hue, float $sat, float $lum): array
{ {
if ($hue == 360) { if ($hue == 360) {
$hue = 0; $hue = 0;
} }
if ($hue < 0 || $hue > 359) { if ($hue < 0 || $hue > 359) {
return false; throw new \LengthException('Argument value ' . $hue . ' for hue is not in the range of 0 to 359', 1);
} }
if ($sat < 0 || $sat > 100) { if ($sat < 0 || $sat > 100) {
return false; throw new \LengthException('Argument value ' . $sat . ' for saturation is not in the range of 0 to 100', 2);
} }
if ($lum < 0 || $lum > 100) { if ($lum < 0 || $lum > 100) {
return false; throw new \LengthException('Argument value ' . $lum . ' for luminance is not in the range of 0 to 100', 3);
} }
// calc to internal convert value for hue // calc to internal convert value for hue
$hue = (1 / 360) * $hue; $hue = (1 / 360) * $hue;

View File

@@ -26,8 +26,12 @@ class SetVarTypeMain
?string $default = null, ?string $default = null,
bool $to_null = false bool $to_null = false
): ?string { ): ?string {
if (is_string($val)) { if (
return $val; $val === null ||
is_scalar($val) ||
$val instanceof \Stringable
) {
return (string)$val;
} }
if ($to_null === false) { if ($to_null === false) {
return (string)$default; return (string)$default;
@@ -39,6 +43,7 @@ class SetVarTypeMain
* Will convert input data to string if possible. * Will convert input data to string if possible.
* Runs for string/int/float/bool/null * Runs for string/int/float/bool/null
* Will skip array/object/resource/callable/etc and use default for that * Will skip array/object/resource/callable/etc and use default for that
* Note: this is pretty much the same as setStrMain because string is easy
* *
* @param mixed $val Input variable * @param mixed $val Input variable
* @param string|null $default Default value * @param string|null $default Default value
@@ -71,6 +76,7 @@ class SetVarTypeMain
/** /**
* If input variable is int, return it, else return default value. If to_null * If input variable is int, return it, else return default value. If to_null
* is true then null as return is allowed, else only int is returned * is true then null as return is allowed, else only int is returned
* Note, if float is sent in, int is returned
* *
* @param mixed $val Input variable * @param mixed $val Input variable
* @param int|null $default Default value * @param int|null $default Default value
@@ -82,8 +88,8 @@ class SetVarTypeMain
?int $default = null, ?int $default = null,
bool $to_null = false bool $to_null = false
): ?int { ): ?int {
if (is_int($val)) { if (is_numeric($val)) {
return $val; return (int)$val;
} }
if ($to_null === false) { if ($to_null === false) {
return (int)$default; return (int)$default;
@@ -129,6 +135,7 @@ class SetVarTypeMain
/** /**
* If input is float return it, else set to default value. If to_null is set * If input is float return it, else set to default value. If to_null is set
* to true, allow null return * to true, allow null return
* Note if an int is sent in, float is returned
* *
* @param mixed $val Input variable * @param mixed $val Input variable
* @param float|null $default Default value * @param float|null $default Default value
@@ -140,8 +147,8 @@ class SetVarTypeMain
?float $default = null, ?float $default = null,
bool $to_null = false bool $to_null = false
): ?float { ): ?float {
if (is_float($val)) { if (is_numeric($val)) {
return $val; return (float)$val;
} }
if ($to_null === false) { if ($to_null === false) {
return (float)$default; return (float)$default;

View File

@@ -48,8 +48,26 @@ class Json
return (array)$json; return (array)$json;
} }
/**
* convert array to json
* Will set empty json {} on false/error
* Error can be read with jsonGetLastError
* Deos not throw errors
*
* @param array<mixed> $data
* @param int $flags json_encode flags as is
* @return string JSON string or '{}' if false
*/
public static function jsonConvertArrayTo(array $data, int $flags = 0): string
{
$json_string = json_encode($data, $flags) ?: '{}';
self::$json_last_error = json_last_error();
return (string)$json_string;
}
/** /**
* returns human readable string for json errors thrown in jsonConvertToArray * returns human readable string for json errors thrown in jsonConvertToArray
* Source: https://www.php.net/manual/en/function.json-last-error.php
* *
* @param bool $return_string [default=false] if set to true * @param bool $return_string [default=false] if set to true
* it will return the message string and not * it will return the message string and not
@@ -80,6 +98,15 @@ class Json
case JSON_ERROR_UTF8: case JSON_ERROR_UTF8:
$json_error_string = 'Malformed UTF-8 characters, possibly incorrectly encoded'; $json_error_string = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break; break;
case JSON_ERROR_RECURSION:
$json_error_string = 'One or more recursive references in the value to be encoded';
break;
case JSON_ERROR_INF_OR_NAN:
$json_error_string = 'One or more NAN or INF values in the value to be encoded';
break;
case JSON_ERROR_UNSUPPORTED_TYPE:
$json_error_string = ' A value of a type that cannot be encoded was given';
break;
case JSON_ERROR_INVALID_PROPERTY_NAME: case JSON_ERROR_INVALID_PROPERTY_NAME:
$json_error_string = 'A key starting with \u0000 character was in the string'; $json_error_string = 'A key starting with \u0000 character was in the string';
break; break;

View File

@@ -15,9 +15,6 @@ namespace CoreLibs\Create;
class Session class Session
{ {
/** @var string list for errors */
private string $session_intern_error_str = '';
/** /**
* init a session, if array is empty or array does not have session_name set * init a session, if array is empty or array does not have session_name set
* then no auto init is run * then no auto init is run
@@ -71,17 +68,6 @@ class Session
return true; return true;
} }
/**
* Return set error string, empty if none set
* Error strings are only set in the startSession method
*
* @return string Last error string
*/
public function getErrorStr(): string
{
return $this->session_intern_error_str;
}
/** /**
* check if session name is valid * check if session name is valid
* *
@@ -120,13 +106,11 @@ class Session
{ {
// we can't start sessions on command line // we can't start sessions on command line
if ($this->checkCliStatus()) { if ($this->checkCliStatus()) {
$this->session_intern_error_str = '[SESSION] No sessions in php cli'; throw new \RuntimeException('[SESSION] No sessions in php cli', 1);
return false;
} }
// if session are OFF // if session are OFF
if ($this->getSessionStatus() === PHP_SESSION_DISABLED) { if ($this->getSessionStatus() === PHP_SESSION_DISABLED) {
$this->session_intern_error_str = '[SESSION] Sessions are disabled'; throw new \RuntimeException('[SESSION] Sessions are disabled', 2);
return false;
} }
// session_status // session_status
// initial the session if there is no session running already // initial the session if there is no session running already
@@ -139,8 +123,7 @@ class Session
if (!empty($session_name)) { if (!empty($session_name)) {
// invalid session name, abort // invalid session name, abort
if (!$this->checkValidSessionName($session_name)) { if (!$this->checkValidSessionName($session_name)) {
$this->session_intern_error_str = '[SESSION] Invalid session name: ' . $session_name; throw new \UnexpectedValueException('[SESSION] Invalid session name: ' . $session_name, 3);
return false;
} }
$this->setSessionName($session_name); $this->setSessionName($session_name);
} }
@@ -149,11 +132,10 @@ class Session
} }
// if we still have no active session // if we still have no active session
if (!$this->checkActiveSession()) { if (!$this->checkActiveSession()) {
$this->session_intern_error_str = '[SESSION] Failed to activate session'; throw new \RuntimeException('[SESSION] Failed to activate session', 4);
return false;
} }
if (false === ($session_id = $this->getSessionId())) { if (false === ($session_id = $this->getSessionId())) {
$this->session_intern_error_str = '[SESSION] getSessionId did not return a session id'; throw new \UnexpectedValueException('[SESSION] getSessionId did not return a session id', 5);
} }
return $session_id; return $session_id;
} }

View File

@@ -61,6 +61,7 @@ class ArrayIO extends \CoreLibs\DB\IO
* @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Logging\Logging $log Logging class
* @param int $base_acl_level Set base acl level, if needed * @param int $base_acl_level Set base acl level, if needed
* @param int $acl_admin Flag if this is an admin ACL access level * @param int $acl_admin Flag if this is an admin ACL access level
* @throws \RuntimeException Missing table array or table name entry
*/ */
public function __construct( public function __construct(
array $db_config, array $db_config,
@@ -83,6 +84,7 @@ class ArrayIO extends \CoreLibs\DB\IO
// error abort if no table array or no table name // error abort if no table array or no table name
if (empty($table_array) || empty($table_name)) { if (empty($table_array) || empty($table_name)) {
$this->__dbError(1999, false, 'MAJOR ERROR: Core settings missing'); $this->__dbError(1999, false, 'MAJOR ERROR: Core settings missing');
throw new \RuntimeException('MAJOR ERROR: Core settings missing', 1999);
} }
// set primary key for given table_array // set primary key for given table_array

View File

@@ -302,14 +302,14 @@ class IO
/** @var string */ /** @var string */
private string $to_encoding = ''; private string $to_encoding = '';
/** @var string the query string at the moment */ /** @var string the query string at the moment */
private string $query; private string $query = '';
/** @var array<mixed> current params for query */ /** @var array<mixed> current params for query */
private array $params; private array $params = [];
// only inside // only inside
// basic vars // basic vars
// the dbh handler, if disconnected by command is null, bool:false on error, // the dbh handler, if disconnected by command is null, bool:false on error,
/** @var \PgSql\Connection|false|null */ /** @var \PgSql\Connection|false|null */
private \PgSql\Connection|false|null $dbh; private \PgSql\Connection|false|null $dbh = null;
/** @var bool DB_DEBUG ... (if set prints out debug msgs) */ /** @var bool DB_DEBUG ... (if set prints out debug msgs) */
private bool $db_debug = false; private bool $db_debug = false;
/** @var string the DB connected to */ /** @var string the DB connected to */
@@ -340,11 +340,12 @@ class IO
// 4: convert numeric/floatN to float (CONVERT_NUMERIC) // 4: convert numeric/floatN to float (CONVERT_NUMERIC)
// 8: convert bytea to string data (CONVERT_BYTEA) // 8: convert bytea to string data (CONVERT_BYTEA)
/** @var int type settings as bit mask, 0 for off, anything >2 will aways set 1 too */ /** @var int type settings as bit mask, 0 for off, anything >2 will aways set 1 too */
/** @phan-suppress-next-line PhanInvalidConstantExpression, PhanUndeclaredClassConstant */
private int $convert_type = Convert::off->value; private int $convert_type = Convert::off->value;
// FOR BELOW: (This should be private and only readable through some method) // FOR BELOW: (This should be private and only readable through some method)
// cursor array for cached readings // cursor array for cached readings
/** @var array<string,mixed> extended cursoers string index with content */ /** @var array<string,mixed> extended cursoers string index with content */
private array $cursor_ext; private array $cursor_ext = [];
// per query vars // per query vars
/** @var \PgSql\Result|false actual cursor (DBH) */ /** @var \PgSql\Result|false actual cursor (DBH) */
private \PgSql\Result|false $cursor; private \PgSql\Result|false $cursor;
@@ -401,7 +402,7 @@ class IO
/** @var bool if we use RETURNING in the INSERT call */ /** @var bool if we use RETURNING in the INSERT call */
private bool $returning_id = false; private bool $returning_id = false;
/** @var string if a sync is running holds the hash key of the query */ /** @var string if a sync is running holds the hash key of the query */
private string $async_running; private string $async_running = '';
// logging class, must be public so settings can be changed // logging class, must be public so settings can be changed
/** @var \CoreLibs\Logging\Logging */ /** @var \CoreLibs\Logging\Logging */
public \CoreLibs\Logging\Logging $log; public \CoreLibs\Logging\Logging $log;
@@ -413,6 +414,7 @@ class IO
* phpcs:ignore * phpcs:ignore
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config DB configuration array * @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config DB configuration array
* @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Logging\Logging $log Logging class
* @throws \RuntimeException If no DB connection can be established on launch
*/ */
public function __construct( public function __construct(
array $db_config, array $db_config,
@@ -491,6 +493,7 @@ class IO
if (!$this->__connectToDB()) { if (!$this->__connectToDB()) {
$this->__dbError(16); $this->__dbError(16);
$this->db_connection_closed = true; $this->db_connection_closed = true;
throw new \RuntimeException('INIT: No DB Handler found / connect or reconnect failed', 16);
} }
} }
@@ -805,7 +808,10 @@ class IO
$call_stack[] = $call_stack[] =
($call_trace['file'] ?? 'n/f') . ':' ($call_trace['file'] ?? 'n/f') . ':'
. ($call_trace['line'] ?? '-') . ':' . ($call_trace['line'] ?? '-') . ':'
. (!empty($call_trace['class']) ? $call_trace['class'] . '->' : '') . (!empty($call_trace['class']) ?
$call_trace['class'] . ($call_trace['type'] ?? '') :
''
)
. $call_trace['function']; . $call_trace['function'];
} }
$context = [ $context = [
@@ -814,18 +820,18 @@ class IO
switch ($id) { switch ($id) {
case 'DB_ERROR': case 'DB_ERROR':
$this->log->error( $this->log->error(
$debug_id . ' :' . $prefix . $error_string, $prefix . $error_string,
$context $context
); );
break; break;
case 'DB_WARNING': case 'DB_WARNING':
$this->log->warning( $this->log->warning(
$debug_id . ' :' . $prefix . $error_string, $prefix . $error_string,
$context $context
); );
break; break;
default: default:
// used named arguments so we can easy change the order of debug // used named arguments so we can easy change the order of debug
$this->log->debug( $this->log->debug(
group_id: $debug_id, group_id: $debug_id,
message: $error_string, message: $error_string,
@@ -970,9 +976,9 @@ class IO
/** /**
* write an error * write an error
* *
* @param integer $error_id Any Error ID, used in debug message string * @param integer $error_id Any Error ID, used in debug message string
* @param \PgSql\Result|false $cursor Optional cursor, passed on to preprocessor * @param \PgSql\Result|false $cursor Optional cursor, passed on to preprocessor
* @param string $msg optional message added to debug * @param string $msg optional message added to debug
* @return void * @return void
*/ */
protected function __dbError( protected function __dbError(
@@ -2057,10 +2063,11 @@ class IO
/** /**
* this is only needed for Postgresql. Converts postgresql arrays to PHP * this is only needed for Postgresql. Converts postgresql arrays to PHP
* Recommended to rather user 'array_to_json' instead and convet JSON in PHP * Recommended to rather user 'array_to_json' instead and convet JSON in PHP
* or if ARRAY_AGG -> JSONB_AGG
* *
* @param string $text input text to parse to an array * @param string $text input text to parse to an array
* @return array<mixed> PHP array of the parsed data * @return array<mixed> PHP array of the parsed data
* @deprecated Recommended to use 'array_to_json' in PostgreSQL instead * @deprecated Recommended to use 'array_to_json/jsonb_agg' in PostgreSQL instead
*/ */
public function dbArrayParse(string $text): array public function dbArrayParse(string $text): array
{ {
@@ -2683,7 +2690,7 @@ class IO
*/ */
public function dbGetCursor(): \PgSql\Result|false public function dbGetCursor(): \PgSql\Result|false
{ {
return $this->cursor; return $this->cursor ?? false;
} }
// *************************** // ***************************
@@ -2740,7 +2747,7 @@ class IO
} }
$query_hash = $this->dbGetQueryHash($query, $params); $query_hash = $this->dbGetQueryHash($query, $params);
if ( if (
is_array($this->cursor_ext) && !empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash]) isset($this->cursor_ext[$query_hash])
) { ) {
if (empty($query_field)) { if (empty($query_field)) {
@@ -2759,9 +2766,9 @@ class IO
* @param string $query Query to find in cursor_ext * @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params * @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional * data to create a unique call one, optional
* @return int|false query position (row pos), false on error * @return int|false|null query position (row pos), false on error
*/ */
public function dbGetCursorPos(string $query, array $params = []): int|false public function dbGetCursorPos(string $query, array $params = []): int|false|null
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
@@ -2769,7 +2776,14 @@ class IO
return false; return false;
} }
$query_hash = $this->dbGetQueryHash($query, $params); $query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['pos']; if (
!empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
return (int)$this->cursor_ext[$query_hash]['pos'];
} else {
return null;
}
} }
/** /**
@@ -2778,9 +2792,9 @@ class IO
* @param string $query Query to find in cursor_ext * @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params * @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional * data to create a unique call one, optional
* @return int|false query position (row pos), false on error * @return int|false|null numer of rows returned, false on error
*/ */
public function dbGetCursorNumRows(string $query, array $params = []): int|false public function dbGetCursorNumRows(string $query, array $params = []): int|false|null
{ {
$this->__dbErrorReset(); $this->__dbErrorReset();
if (!$query) { if (!$query) {
@@ -2788,7 +2802,14 @@ class IO
return false; return false;
} }
$query_hash = $this->dbGetQueryHash($query, $params); $query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['num_rows']; if (
!empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
return (int)$this->cursor_ext[$query_hash]['num_rows'];
} else {
return null;
}
} }
// *************************** // ***************************
@@ -3190,7 +3211,7 @@ class IO
/** /**
* Returns the current async running query hash * Returns the current async running query hash
* *
* @return string Current async running query hash * @return string Current async running query hash, empty string for nothing
*/ */
public function dbGetAsyncRunning(): string public function dbGetAsyncRunning(): string
{ {
@@ -3735,7 +3756,7 @@ class IO
* Either a single element for a single insert or an array * Either a single element for a single insert or an array
* if multiple insert values where used. * if multiple insert values where used.
* *
* @return array<mixed>|string|int|null Current insert query primary key * @return array<mixed>|string|int|null Current insert query primary key, null on not set
*/ */
public function dbGetInsertPK(): array|string|int|null public function dbGetInsertPK(): array|string|int|null
{ {
@@ -3825,7 +3846,7 @@ class IO
*/ */
public function dbGetNumRows(): ?int public function dbGetNumRows(): ?int
{ {
return $this->num_rows; return $this->num_rows ?? null;
} }
/** /**
@@ -3835,10 +3856,7 @@ class IO
*/ */
public function dbGetNumFields(): ?int public function dbGetNumFields(): ?int
{ {
if (!isset($this->num_fields)) { return $this->num_fields ?? null;
return null;
}
return $this->num_fields;
} }
/** /**

View File

@@ -63,7 +63,7 @@ class FileWriter
* *
* @param string $string string to write to the file * @param string $string string to write to the file
* @param boolean $enter default true, if set adds a linebreak \n at the end * @param boolean $enter default true, if set adds a linebreak \n at the end
* @return bool True for log written, false for not wirrten * @return bool True for log written, false for not written
*/ */
public static function fdebug(string $string, bool $enter = true): bool public static function fdebug(string $string, bool $enter = true): bool
{ {
@@ -75,7 +75,7 @@ class FileWriter
empty(self::$debug_folder) && empty(self::$debug_folder) &&
defined('BASE') && defined('LOG') defined('BASE') && defined('LOG')
) { ) {
/** @deprecated Do not use this anymore, define path with fsetFolder */ /** @deprecated Do not use this anymore, define path with festFolder */
trigger_error( trigger_error(
'fsetFolder must be set first. Setting via LOG_FILE_ID and LOG constants is deprecated', 'fsetFolder must be set first. Setting via LOG_FILE_ID and LOG constants is deprecated',
E_USER_DEPRECATED E_USER_DEPRECATED

View File

@@ -405,7 +405,7 @@ class LoggingLegacy
// set per class, but don't use get_class as we will only get self // set per class, but don't use get_class as we will only get self
$rpl_string = !$this->log_per_class ? '' : '_' $rpl_string = !$this->log_per_class ? '' : '_'
// set sub class settings // set sub class settings
. str_replace('\\', '-', Support::getCallerClass()); . str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file // if request to write to one file
@@ -756,7 +756,7 @@ class LoggingLegacy
return $status; return $status;
} }
// get the last class entry and wrie that // get the last class entry and wrie that
$class = Support::getCallerClass(); $class = Support::getCallerTopLevelClass();
// get timestamp // get timestamp
$timestamp = Support::printTime(); $timestamp = Support::printTime();
// same string put for print (no html data inside) // same string put for print (no html data inside)
@@ -855,7 +855,7 @@ class LoggingLegacy
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; ' . 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">' . 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">' . '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. Support::getCallerClass() . '</span>}</div>'; . Support::getCallerTopLevelClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output $string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> ' . '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>' . $script_end . '</div>'

View File

@@ -79,10 +79,10 @@ class Support
* default true: true, false: false * default true: true, false: false
* *
* @param bool $bool Variable to convert * @param bool $bool Variable to convert
* @param string $name [default: ''] Prefix name * @param string $name [=''] Prefix name
* @param string $true [default: 'true'] True string * @param string $true [='true'] True string
* @param string $false [default: 'false'] False string * @param string $false [='false'] False string
* @param bool $no_html [default: false] if true do not print html * @param bool $no_html [=false] if true do not print html
* @return string String with converted bool text for debug * @return string String with converted bool text for debug
*/ */
public static function printBool( public static function printBool(
@@ -104,8 +104,8 @@ class Support
* Convert bool value to string value. Short name alias for printBool * Convert bool value to string value. Short name alias for printBool
* *
* @param bool $bool Bool value to be transformed * @param bool $bool Bool value to be transformed
* @param string $true [default: 'true'] Override default string 'true' * @param string $true [='true'] Override default string 'true'
* @param string $false [default: 'false'] Override default string 'false' * @param string $false [=false'] Override default string 'false'
* @return string $true or $false string for true/false bool * @return string $true or $false string for true/false bool
*/ */
public static function prBl( public static function prBl(
@@ -159,7 +159,7 @@ class Support
* Recommended debug output * Recommended debug output
* *
* @param mixed $data Anything * @param mixed $data Anything
* @param bool $no_html [default=false] If true strip all html tags * @param bool $no_html [=false] If true strip all html tags
* (for text print) * (for text print)
* @return string A text string * @return string A text string
*/ */
@@ -203,7 +203,7 @@ class Support
* exports (dumps) var, in more printable design, but without detail info * exports (dumps) var, in more printable design, but without detail info
* *
* @param mixed $data Anything * @param mixed $data Anything
* @param bool $no_html If true true do not add <pre> tags * @param bool $no_html [=false] If true true do not add <pre> tags
* @return string A text string * @return string A text string
*/ */
public static function exportVar(mixed $data, bool $no_html = false): string public static function exportVar(mixed $data, bool $no_html = false): string
@@ -217,7 +217,7 @@ class Support
* Return file name and line number where this was called * Return file name and line number where this was called
* One level up * One level up
* *
* @param int $level trace level, default 1 * @param int $level [=1] trace level
* @return string|null null or file name:line number * @return string|null null or file name:line number
*/ */
public static function getCallerFileLine(int $level = 1): ?string public static function getCallerFileLine(int $level = 1): ?string
@@ -238,14 +238,14 @@ class Support
* eg for debugging, this function does this * eg for debugging, this function does this
* *
* call this method in the child method and you get the parent function that called * call this method in the child method and you get the parent function that called
* @param int $level trace level, default 1 * @param int $level [=1] trace level
* @return ?string null or the function that called the function * @return string|null null or the function that called the function
* where this method is called * where this method is called
*/ */
public static function getCallerMethod(int $level = 1): ?string public static function getCallerMethod(int $level = 1): ?string
{ {
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print \CoreLibs\Debug\Support::printAr($traces); // print "getCallerMethod:<br>" . \CoreLibs\Debug\Support::printAr($traces);
// We should check from top down if unset? // We should check from top down if unset?
// sets the start point here, and in level two (the sub call) we find this // sets the start point here, and in level two (the sub call) we find this
if (isset($traces[$level])) { if (isset($traces[$level])) {
@@ -254,6 +254,41 @@ class Support
return null; return null;
} }
/**
* get the class that first called it and skip the base class
* Companion method to getCallerMethod
*
* @param int $level [=1] trace level
* @return ?string null if class not found
*/
public static function getCallerClass(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return $traces[$level]['class'] ?? null;
}
return null;
}
/**
* Returns class and method together
*
* @param int $level [=1] travel level
* @return string|null null if trace level not found, else namespace class and method
*/
public static function getCallerClassMethod(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return ($traces[$level]['class'] ?? '-')
. ($traces[$level]['type'] ?? '')
. $traces[$level]['function'];
}
return null;
}
/** /**
* Returns array with all methods in the call stack in the order so that last * Returns array with all methods in the call stack in the order so that last
* called is last in order * called is last in order
@@ -283,25 +318,21 @@ class Support
* Is mostly used in debug log statements to get the class where the debug * Is mostly used in debug log statements to get the class where the debug
* was called * was called
* gets top level class * gets top level class
* loops over the debug backtrace until if finds the first class (from the end) * loops over the debug backtrace until if finds the first class (from the end)
* *
* @return string Class name with namespace * @return string Class name with namespace
*/ */
public static function getCallerClass(): string public static function getCallerTopLevelClass(): string
{ {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// ?? [['class' => get_called_class()]]; // print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
// TODO make sure that this doesn't loop forver
$class = null; $class = null;
while ($class === null && count($backtrace) > 0) { // reverse and stop at first set class, this is the top level one
// if current is foreach (array_reverse($traces) as $trace) {
// [function] => debug $class = $trace['class'] ?? null;
// [class] => CoreLibs\Debug\Logging if (!empty($class)) {
// then return break;
// (OUTSIDE) because it was not called from a class method }
// or return file name
$get_class = array_pop($backtrace);
$class = $get_class['class'] ?? null;
} }
// on null or empty return empty string // on null or empty return empty string
return empty($class) ? '' : $class; return empty($class) ? '' : $class;

View File

@@ -254,7 +254,7 @@ class L10n
} }
// if this is still null here, we abort // if this is still null here, we abort
if ($this->l10n === null) { if ($this->l10n === null) {
throw new \Exception( throw new \RuntimeException(
"Could not create CoreLibs\Language\Core\GetTextReader object", "Could not create CoreLibs\Language\Core\GetTextReader object",
E_USER_ERROR E_USER_ERROR
); );

View File

@@ -0,0 +1,167 @@
<?php
/**
* AUTOR: Clemens Schwaighofer
* CREATED: 2023/9/7
* DESCRIPTION:
* General error collection class for output to frontend or to log
*/
declare(strict_types=1);
namespace CoreLibs\Logging;
use CoreLibs\Logging\Logger\MessageLevel;
class ErrorMessage
{
/** @var array<int,array{id:string,level:string,str:string,target:string,highlight:string[]}> */
private array $error_str = [];
/** @var \CoreLibs\Logging\Logging $log */
public \CoreLibs\Logging\Logging $log;
public function __construct(
\CoreLibs\Logging\Logging $log
) {
$this->log = $log;
}
/**
* pushes new error message into the error_str array
* error_id: internal Error ID (should be unique)
* level: error level, can only be ok, info, warn, error, abort, crash
* ok and info are positive response: success
* warn: success, but there might be some things that are not 100% ok
* error: input error or error in executing request
* abort: an internal error happened as mandatory information that normally is
* there is missing, or the ACL level that should normally match does not
* will be logged to "critical"
* crash: system failure or critical system problems (db connection failure)
* will be logged as "alert"
* not set: unkown, will be logged as "emergency"
* target/highlight: id target name for frontend where to attach this message
* highlight is a list of other target points to highlight
*
* @param string $error_id Any internal error ID for this error
* @param string $level Error level in ok/info/warn/error
* @param string $str Error message (out)
* @param string $target alternate attachment point for this error message
* @param array<string> $highlight Any additional error data as error OR
* highlight points for field highlights
* @param string|null $message If abort/crash, non localized $str
* @param array<mixed> $context Additionl info for abort/crash messages
*/
public function setErrorMsg(
string $error_id,
string $level,
string $str,
string $target = '',
array $highlight = [],
?string $message = null,
array $context = [],
): void {
$original_level = $level;
$level = MessageLevel::fromName($level)->name;
// if not string set, write message string if set, else level/error id
if (empty($str)) {
$str = $message ?? 'L:' . $level . '|E:' . $error_id;
}
$this->error_str[] = [
'id' => $error_id,
'level' => $level,
'str' => $str,
'target' => $target,
'highlight' => $highlight,
];
// write to log for abort/crash
switch ($level) {
case 'abort':
$this->log->critical($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
case 'crash':
$this->log->alert($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
case 'unknown':
$this->log->emergency($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
}
}
/**
* pushes new error message into the error_str array
* Note, the parameter order is different and does not need an error id
* This is for backend alerts
*
* @param string $level error level (ok/warn/info/error)
* @param string $str error string
* @param string|null $error_id optional error id for precise error lookup
* @param string $target Alternate id name for output target on frontend
* @param array<string> $highlight Any additional error data as error OR
* highlight points for field highlights
* @param string|null $message If abort/crash, non localized $str
* @param array<mixed> $context Additionl info for abort/crash messages
*/
public function setErrorMsgLevel(
string $level,
string $str,
?string $error_id = null,
string $target = '',
array $highlight = [],
?string $message = null,
array $context = [],
): void {
$this->setErrorMsg($error_id ?? '', $level, $str, $target, $highlight, $message, $context);
}
// *********************************************************************
// GETTERS
// *********************************************************************
/**
* Returns the current set error content from setErrorMsg method
*
* @return array<int,array{id:string,level:string,str:string,target:string,highlight:string[]}> Error messages array
*/
public function getErrorMsg(): array
{
return $this->error_str;
}
/**
* Current set error ids
*
* @return array<string>
*/
public function getErrorIds(): array
{
return array_column($this->error_str, 'id');
}
/**
* Gets the LAST entry in the array list.
* If nothing found returns empty array set
*
* @return array{id:string,level:string,str:string,target:string,highlight:string[]} Error block
*/
public function getLastErrorMsg(): array
{
return $this->error_str[array_key_last($this->error_str)] ?? [
'level' => '',
'str' => '',
'id' => '',
'target' => '',
'highlight' => [],
];
}
}
// __END__

View File

@@ -113,17 +113,32 @@ enum Level: int
/** /**
* Returns true if the passed $level is higher or equal to $this * Returns true if the passed $level is higher or equal to $this
*
* @param Level $level
* @return bool
*/ */
public function includes(Level $level): bool public function includes(Level $level): bool
{ {
return $this->value <= $level->value; return $this->value <= $level->value;
} }
/**
* If level is higher than set one
*
* @param Level $level
* @return bool
*/
public function isHigherThan(Level $level): bool public function isHigherThan(Level $level): bool
{ {
return $this->value > $level->value; return $this->value > $level->value;
} }
/**
* if level is lower than set one
*
* @param Level $level
* @return bool
*/
public function isLowerThan(Level $level): bool public function isLowerThan(Level $level): bool
{ {
return $this->value < $level->value; return $this->value < $level->value;

View File

@@ -0,0 +1,51 @@
<?php // phpcs:disable Generic.Files.LineLength
/**
* AUTOR: Clemens Schwaighofer
* CREATED: 2023-09-08
* DESCRIPTION:
* Error message return levels
*/
declare(strict_types=1);
namespace CoreLibs\Logging\Logger;
enum MessageLevel: int
{
case ok = 100;
case info = 200;
case warn = 300;
case error = 400;
case abort = 500;
case crash = 550;
case unknown = 600;
/**
* @param string $name any string name, if not matching use unkown
* @return static
*/
public static function fromName(string $name): self
{
return match (strtolower($name)) {
'ok' => self::ok,
'info' => self::info,
'warn', 'warning' => self::warn,
'error' => self::error,
'abort' => self::abort,
'crash' => self::crash,
default => self::unknown,
};
}
/**
* @param int $value
* @return static
*/
public static function fromValue(int $value): self
{
return self::tryFrom($value) ?? self::unknown;
}
}
// __END__

View File

@@ -381,7 +381,7 @@ class Logging
// auto set (should be deprecated in future) // auto set (should be deprecated in future)
$this->setLogFileId( $this->setLogFileId(
str_replace(':', '-', $this->host_name) . '_' str_replace(':', '-', $this->host_name) . '_'
. str_replace('\\', '-', Support::getCallerClass()) . str_replace('\\', '-', Support::getCallerTopLevelClass())
); );
} }
if (empty($this->getLogFileId())) { if (empty($this->getLogFileId())) {
@@ -460,7 +460,7 @@ class Logging
// set per class, but don't use get_class as we will only get self // set per class, but don't use get_class as we will only get self
$rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_' $rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_'
// set sub class settings // set sub class settings
. str_replace('\\', '-', Support::getCallerClass()); . str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file // if request to write to one file
@@ -526,7 +526,10 @@ class Logging
/** /**
* Prepare the log message with all needed info blocks: * Prepare the log message with all needed info blocks:
* [timestamp] [host name] [file path + file] [running uid] {class} <debug level/group id> - message * [timestamp] [host name] [file path + file::row number] [running uid] {class::/->method}
* <debug level:debug group id> - message
* Note: group id is only for debug level
* if no method can be found or no class is found a - will be wirtten
* *
* @param Level $level Log level we will write to * @param Level $level Log level we will write to
* @param string|Stringable $message The message to write * @param string|Stringable $message The message to write
@@ -545,16 +548,32 @@ class Logging
if (!$this->checkLogLevel($level)) { if (!$this->checkLogLevel($level)) {
return ''; return '';
} }
$file_line = '';
$caller_class_method = '-';
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "[" . $level->getName() . "] [$message] prepareLog:<br>" . Support::printAr($traces);
// file + line: call not this but one before (the one that calls this) // file + line: call not this but one before (the one that calls this)
$file_line = Support::getCallerFileLine(2) ?? // start from this level, if unset fall down until we are at null
System::getPageName(System::FULL_PATH); $start_trace_level = 2;
// get the last class entry and wrie that for ($trace_level = $start_trace_level; $trace_level >= 0; $trace_level--) {
$class = Support::getCallerClass(); if (isset($traces[$trace_level])) {
// method/function: prepareLog->(debug|info|...)->[THIS] $file_line = ($traces[$trace_level]['file'] ?? $traces[$trace_level]['function'])
$method = Support::getCallerMethod(3); . ':' . ($traces[$trace_level]['line'] ?? '-');
if ($method !== null) { // as namespace\class->method
$class .= '::' . $method; $caller_class_method =
// get the last call before we are in the Logging class
($traces[$trace_level]['class'] ?? '')
// connector, if unkown use ==
. ($traces[$trace_level]['type'] ?? '')
// method/function: prepareLog->(debug|info|...)->[THIS]
. $traces[$trace_level]['function'];
break;
}
} }
if (empty($file_line)) {
$file_line = System::getPageName(System::FULL_PATH);
}
// print "CLASS: " . $class . "<br>";
// get timestamp // get timestamp
$timestamp = Support::printTime(); $timestamp = Support::printTime();
@@ -574,7 +593,7 @@ class Logging
. '[' . $this->host_name . '] ' . '[' . $this->host_name . '] '
. '[' . $file_line . '] ' . '[' . $file_line . '] '
. '[' . $this->running_uid . '] ' . '[' . $this->running_uid . '] '
. '{' . $class . '} ' . '{' . $caller_class_method . '} '
. '<' . strtoupper($group_str) . '> ' . '<' . strtoupper($group_str) . '> '
. $message . $message
. $context_str; . $context_str;

View File

@@ -23,7 +23,8 @@ class Image
* if empty ROOT is choosen * if empty ROOT is choosen
* @param string $cache_source cache path, if not given TMP is used * @param string $cache_source cache path, if not given TMP is used
* @param bool $clear_cache if set to true, will create thumb all the tame * @param bool $clear_cache if set to true, will create thumb all the tame
* @return string|false thumbnail name, or false for error * @return string thumbnail name
* @throws \RuntimeException no ImageMagick convert command found
*/ */
public static function createThumbnail( public static function createThumbnail(
string $pic, string $pic,
@@ -33,7 +34,7 @@ class Image
string $path = '', string $path = '',
string $cache_source = '', string $cache_source = '',
bool $clear_cache = false bool $clear_cache = false
): string|false { ): string {
// get image type flags // get image type flags
$image_types = [ $image_types = [
0 => 'UNKOWN-IMAGE', 0 => 'UNKOWN-IMAGE',
@@ -41,7 +42,7 @@ class Image
2 => 'jpg', 2 => 'jpg',
3 => 'png' 3 => 'png'
]; ];
$return_data = false; $return_data = '';
$CONVERT = ''; $CONVERT = '';
// if CONVERT is not defined, abort // if CONVERT is not defined, abort
/** @phan-suppress-next-line PhanUndeclaredConstant */ /** @phan-suppress-next-line PhanUndeclaredConstant */
@@ -49,7 +50,7 @@ class Image
/** @phan-suppress-next-line PhanUndeclaredConstant */ /** @phan-suppress-next-line PhanUndeclaredConstant */
$CONVERT = CONVERT; $CONVERT = CONVERT;
} else { } else {
return $return_data; throw new \RuntimeException('CONVERT set binary is not executable or CONVERT is not defined');
} }
if (!empty($cache_source)) { if (!empty($cache_source)) {
$tmp_src = $cache_source; $tmp_src = $cache_source;
@@ -69,72 +70,7 @@ class Image
$pic = $tmp[(count($tmp) - 1)]; $pic = $tmp[(count($tmp) - 1)];
} }
// does this picture exist and is it a picture // does this picture exist and is it a picture
if (file_exists($filename) && is_file($filename)) { if (!file_exists($filename) || !is_file($filename)) {
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
$convert_prefix = '';
$create_file = false;
$delete_filename = '';
// check if we can skip the PDF creation: if we have size, if do not have type, we assume type png
if (!$type) {
$check_thumb = $tmp_src . 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[3];
if (!is_file($check_thumb)) {
$create_file = true;
} else {
$type = 3;
}
}
// if type is not in the list, but returns as PDF, we need to convert to JPEG before
if (!$type) {
$output = [];
$return = null;
// is this a PDF, if no, return from here with nothing
$convert_prefix = 'png:';
# TEMP convert to PNG, we then override the file name
$convert_string = $CONVERT . ' ' . $filename . ' ' . $convert_prefix . $filename . '_TEMP';
$status = exec($convert_string, $output, $return);
$filename .= '_TEMP';
// for delete, in case we need to glob
$delete_filename = $filename;
// find file, if we can't find base name, use -0 as the first one (ignore other pages in multiple ones)
if (!is_file($filename)) {
$filename .= '-0';
}
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
}
// if no size given, set size to original
if (!$size_x || $size_x < 1) {
$size_x = $width;
}
if (!$size_y || $size_y < 1) {
$size_y = $height;
}
$thumb = 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[$type];
$thumbnail = $tmp_src . $thumb;
// check if we already have this picture converted
if (!is_file($thumbnail) || $clear_cache == true) {
// convert the picture
if ($width > $size_x) {
$convert_string = $CONVERT . ' -geometry ' . $size_x . 'x ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
// get the size of the converted data, if converted
if (is_file($thumbnail)) {
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
}
}
if ($height > $size_y) {
$convert_string = $CONVERT . ' -geometry x' . $size_y . ' ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
}
}
if (!is_file($thumbnail)) {
copy($filename, $thumbnail);
}
$return_data = $thumb;
// if we have a delete filename, delete here with glob
if ($delete_filename) {
array_map('unlink', glob($delete_filename . '*') ?: []);
}
} else {
if (!empty($dummy) && strstr($dummy, '/') === false) { if (!empty($dummy) && strstr($dummy, '/') === false) {
// check if we have the "dummy" image flag set // check if we have the "dummy" image flag set
$filename = PICTURES . ICONS . strtoupper($dummy) . ".png"; $filename = PICTURES . ICONS . strtoupper($dummy) . ".png";
@@ -142,11 +78,77 @@ class Image
if (!empty($dummy) && file_exists($filename) && is_file($filename)) { if (!empty($dummy) && file_exists($filename) && is_file($filename)) {
$return_data = $filename; $return_data = $filename;
} else { } else {
$return_data = false; throw new \Exception('Could not set dummy return file: ' . $dummy . ' in ' . $filename);
} }
} else { } else {
$filename = $dummy; $return_data = $dummy;
} }
return $return_data;
}
// resize image
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
$convert_prefix = '';
$create_file = false;
$delete_filename = '';
// check if we can skip the PDF creation: if we have size, if do not have type, we assume type png
if (!$type) {
$check_thumb = $tmp_src . 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[3];
if (!is_file($check_thumb)) {
$create_file = true;
} else {
$type = 3;
}
}
// if type is not in the list, but returns as PDF, we need to convert to JPEG before
if (!$type) {
$output = [];
$return = null;
// is this a PDF, if no, return from here with nothing
$convert_prefix = 'png:';
# TEMP convert to PNG, we then override the file name
$convert_string = $CONVERT . ' ' . $filename . ' ' . $convert_prefix . $filename . '_TEMP';
$status = exec($convert_string, $output, $return);
$filename .= '_TEMP';
// for delete, in case we need to glob
$delete_filename = $filename;
// find file, if we can't find base name, use -0 as the first one (ignore other pages in multiple ones)
if (!is_file($filename)) {
$filename .= '-0';
}
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
}
// if no size given, set size to original
if (!$size_x || $size_x < 1) {
$size_x = $width;
}
if (!$size_y || $size_y < 1) {
$size_y = $height;
}
$thumb = 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[$type];
$thumbnail = $tmp_src . $thumb;
// check if we already have this picture converted
if (!is_file($thumbnail) || $clear_cache == true) {
// convert the picture
if ($width > $size_x) {
$convert_string = $CONVERT . ' -geometry ' . $size_x . 'x ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
// get the size of the converted data, if converted
if (is_file($thumbnail)) {
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
}
}
if ($height > $size_y) {
$convert_string = $CONVERT . ' -geometry x' . $size_y . ' ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
}
}
if (!is_file($thumbnail)) {
copy($filename, $thumbnail);
}
$return_data = $thumb;
// if we have a delete filename, delete here with glob
if ($delete_filename) {
array_map('unlink', glob($delete_filename . '*') ?: []);
} }
return $return_data; return $return_data;
} }
@@ -173,7 +175,9 @@ class Image
* set to false to not use (default true) * set to false to not use (default true)
* to use quick but less nice version * to use quick but less nice version
* @param int $jpeg_quality default 80, set image quality for jpeg only * @param int $jpeg_quality default 80, set image quality for jpeg only
* @return string|false thumbnail with path * @return string thumbnail with path
* @throws \UnexpectedValueException input values for filename or cache_folder are wrong
* @throws \RuntimeException convert (gd) failed
*/ */
public static function createThumbnailSimple( public static function createThumbnailSimple(
string $filename, string $filename,
@@ -185,8 +189,9 @@ class Image
bool $use_cache = true, bool $use_cache = true,
bool $high_quality = true, bool $high_quality = true,
int $jpeg_quality = 80 int $jpeg_quality = 80
): string|false { ): string {
$thumbnail = false; $thumbnail = false;
$exception_message = 'Could not create thumbnail';
// $this->debug('IMAGE PREPARE', "FILE: $filename (exists " // $this->debug('IMAGE PREPARE', "FILE: $filename (exists "
// .(string)file_exists($filename)."), WIDTH: $thumb_width, HEIGHT: $thumb_height"); // .(string)file_exists($filename)."), WIDTH: $thumb_width, HEIGHT: $thumb_height");
if ( if (
@@ -210,12 +215,17 @@ class Image
} }
// check that input image exists and is either jpeg or png // check that input image exists and is either jpeg or png
// also fail if the basic CACHE folder does not exist at all // also fail if the basic CACHE folder does not exist at all
if ( if (!file_exists($filename)) {
!file_exists($filename) || // return $thumbnail;
!is_dir($cache_folder) || throw new \UnexpectedValueException('Missing image file: ' . $filename);
!is_writable($cache_folder) }
) { if (!is_dir($cache_folder)) {
return $thumbnail; // return $thumbnail;
throw new \UnexpectedValueException('Cache folder is not a directory: ' . $cache_folder);
}
if (!is_writable($cache_folder)) {
// return $thumbnail;
throw new \UnexpectedValueException('Cache folder is not writeable: ' . $cache_folder);
} }
// $this->debug('IMAGE PREPARE', "FILENAME OK, THUMB WIDTH/HEIGHT OK"); // $this->debug('IMAGE PREPARE', "FILENAME OK, THUMB WIDTH/HEIGHT OK");
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null]; [$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
@@ -280,12 +290,18 @@ class Image
// image, copy source image, offset in image, source x/y, new size, source image size // image, copy source image, offset in image, source x/y, new size, source image size
$thumb = imagecreatetruecolor($thumb_width_r, $thumb_height_r); $thumb = imagecreatetruecolor($thumb_width_r, $thumb_height_r);
if ($thumb === false) { if ($thumb === false) {
return false; throw new \RuntimeException(
'imagecreatetruecolor failed: ' . $thumbnail . ', ' . $filename,
1
);
} }
if ($img_type == IMAGETYPE_PNG) { if ($img_type == IMAGETYPE_PNG) {
$imagecolorallocatealpha = imagecolorallocatealpha($thumb, 0, 0, 0, 127); $imagecolorallocatealpha = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
if ($imagecolorallocatealpha === false) { if ($imagecolorallocatealpha === false) {
return false; throw new \RuntimeException(
'imagecolorallocatealpha failed: ' . $thumbnail . ', ' . $filename,
2
);
} }
// preservere transaprency // preservere transaprency
imagecolortransparent( imagecolortransparent(
@@ -347,7 +363,10 @@ class Image
imagedestroy($source); imagedestroy($source);
imagedestroy($thumb); imagedestroy($thumb);
} else { } else {
$thumbnail = false; throw new \RuntimeException(
'Invalid source image file. Only JPEG/PNG are allowed: ' . $filename,
3
);
} }
} }
} else { } else {
@@ -388,14 +407,20 @@ class Image
} }
$thumb = imagecreatetruecolor($thumb_width, $thumb_height); $thumb = imagecreatetruecolor($thumb_width, $thumb_height);
if ($thumb === false) { if ($thumb === false) {
return false; throw new \RuntimeException(
'imagecreatetruecolor dummy failed: ' . $thumbnail . ', ' . $filename,
3
);
} }
// add outside border px = 5% (rounded up) // add outside border px = 5% (rounded up)
// eg 50px -> 2.5px // eg 50px -> 2.5px
$gray = imagecolorallocate($thumb, 200, 200, 200); $gray = imagecolorallocate($thumb, 200, 200, 200);
$white = imagecolorallocate($thumb, 255, 255, 255); $white = imagecolorallocate($thumb, 255, 255, 255);
if ($gray === false || $white === false) { if ($gray === false || $white === false) {
return false; throw new \RuntimeException(
'imagecolorallocate/imagecolorallocate dummy failed: ' . $thumbnail . ', ' . $filename,
2
);
} }
// fill gray background // fill gray background
imagefill($thumb, 0, 0, $gray); imagefill($thumb, 0, 0, $gray);
@@ -430,7 +455,11 @@ class Image
// add web path // add web path
$thumbnail = $thumbnail_web_path . $thumbnail; $thumbnail = $thumbnail_web_path . $thumbnail;
} }
// either return false or the thumbnail name + output path web // if still false -> throw exception
if ($thumbnail === false) {
throw new \RuntimeException($exception_message);
}
// else return the thumbnail name + output path web
return $thumbnail; return $thumbnail;
} }

View File

@@ -27,6 +27,7 @@ class SymmetricEncryption
* @param string $message Message to encrypt * @param string $message Message to encrypt
* @param string $key Encryption key (as hex string) * @param string $key Encryption key (as hex string)
* @return string * @return string
* @throws \Exception
* @throws \RangeException * @throws \RangeException
*/ */
public static function encrypt(string $message, string $key): string public static function encrypt(string $message, string $key): string
@@ -34,7 +35,7 @@ class SymmetricEncryption
try { try {
$key = CreateKey::hex2bin($key); $key = CreateKey::hex2bin($key);
} catch (SodiumException $e) { } catch (SodiumException $e) {
throw new \Exception('Invalid hex key'); throw new \UnexpectedValueException('Invalid hex key');
} }
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) { if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new \RangeException( throw new \RangeException(
@@ -84,10 +85,10 @@ class SymmetricEncryption
$key $key
); );
} catch (SodiumException $e) { } catch (SodiumException $e) {
throw new \Exception('Invalid ciphertext (too short)'); throw new \UnexpectedValueException('Invalid ciphertext (too short)');
} }
if (!is_string($plain)) { if (!is_string($plain)) {
throw new \Exception('Invalid Key'); throw new \UnexpectedValueException('Invalid Key');
} }
sodium_memzero($ciphertext); sodium_memzero($ciphertext);
sodium_memzero($key); sodium_memzero($key);

View File

@@ -167,8 +167,10 @@ final class CoreLibsACLLoginTest extends TestCase
// change_password, pw_username, pw_old_password, pw_new_password, // change_password, pw_username, pw_old_password, pw_new_password,
// pw_new_password_confirm // pw_new_password_confirm
// 3[session]: override session set // 3[session]: override session set
// 4[error] : expected error code, 0 for all ok, 3000 for login page view // 4[error] : expected error code, 0 for all ok, 100 for login page view
// note that 1000 (no db), 2000 (no session) must be tested too // note that 1000 (no db), 2000 (no session), 3000 (options set error)
// must be tested too
// <1000 info, >=1000 critical error
// 5[return] : expected return array, eg login_error code, // 5[return] : expected return array, eg login_error code,
// or other info data to match // or other info data to match
$tests = [ $tests = [
@@ -180,7 +182,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -198,7 +200,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -221,7 +223,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -308,7 +310,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -329,7 +331,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -350,7 +352,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -371,7 +373,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -395,7 +397,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
// default password is plain text // default password is plain text
'login_error' => 1012, 'login_error' => 1012,
@@ -421,7 +423,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 106, 'login_error' => 106,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -446,7 +448,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 104, 'login_error' => 104,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -471,7 +473,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 105, 'login_error' => 105,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -520,7 +522,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -574,7 +576,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -600,7 +602,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -625,7 +627,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 108, 'login_error' => 108,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -761,7 +763,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -853,7 +855,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1101, 'login_error' => 1101,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -909,7 +911,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -965,7 +967,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -992,7 +994,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -1133,7 +1135,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1227,7 +1229,11 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']); $login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']);
// temporary wrong password // temporary wrong password
$_POST['login_password'] = 'wrong'; $_POST['login_password'] = 'wrong';
for ($run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount(); $run <= $max_run; $run++) { for (
$run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount();
$run <= $max_run;
$run++
) {
try { try {
$login_mock->loginMainCall(); $login_mock->loginMainCall();
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -1475,10 +1481,10 @@ final class CoreLibsACLLoginTest extends TestCase
// print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n"; // print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n";
// print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n"; // print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n";
// print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n"; // print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n";
// if this is 3000, then we do further error checks // if this is 100, then we do further error checks
if ( if (
$e->getCode() == 3000 || $e->getCode() == 100 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 3000 !empty($_POST['login_exit']) && $_POST['login_exit'] == 100
) { ) {
$this->assertEquals( $this->assertEquals(
$expected['login_error'], $expected['login_error'],
@@ -1816,7 +1822,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1930,7 +1936,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -2018,7 +2024,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -2114,7 +2120,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );

View File

@@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase;
*/ */
final class CoreLibsCheckColorsTest extends TestCase final class CoreLibsCheckColorsTest extends TestCase
{ {
/**
* Undocumented function
*
* @return array<mixed>
*/
public function validateColorProvider(): array public function validateColorProvider(): array
{ {
/* /*
@@ -321,7 +326,7 @@ final class CoreLibsCheckColorsTest extends TestCase
*/ */
public function testValidateColorException(int $flag): void public function testValidateColorException(int $flag): void
{ {
$this->expectException(\Exception::class); $this->expectException(\UnexpectedValueException::class);
\CoreLibs\Check\Colors::validateColor('#ffffff', $flag); \CoreLibs\Check\Colors::validateColor('#ffffff', $flag);
} }
} }

View File

@@ -518,17 +518,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
return [ return [
// error <2 arguments // error <2 arguments
'too view arguments' => [ 'too view arguments' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1] [1]
], ],
// error <2 arrays // error <2 arrays
'only one array' => [ 'only one array' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1], [1],
true, true,
], ],
// error element is not array // error element is not array
'non array between array' => [ 'non array between array' => [
'TypeError',
'arrayMergeRecursive encountered a non array argument', 'arrayMergeRecursive encountered a non array argument',
[1], [1],
'string', 'string',
@@ -947,18 +950,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/ */
public function testArrayMergeRecursiveWarningA(): void public function testArrayMergeRecursiveWarningA(): void
{ {
set_error_handler( // set_error_handler(
static function (int $errno, string $errstr): never { // static function (int $errno, string $errstr): never {
throw new Exception($errstr, $errno); // throw new Exception($errstr, $errno);
}, // },
E_USER_WARNING // E_USER_WARNING
); // );
$arrays = func_get_args(); $arrays = func_get_args();
// first is expected warning // first is expected warning
$exception = array_shift($arrays);
$warning = array_shift($arrays); $warning = array_shift($arrays);
// phpunit 10.0 compatible // phpunit 10.0 compatible
$this->expectException($exception);
$this->expectExceptionMessage($warning); $this->expectExceptionMessage($warning);
\CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays); \CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays);

View File

@@ -309,45 +309,73 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal' => [ 'dates equal' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller' => [ 'second date smaller' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'dates equal with different time' => [ 'dates equal with different time' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
0, 0,
null,
null,
], ],
'invalid dates --' => [ 'invalid dates --' => [
'--', '--',
'--', '--',
false false,
'UnexpectedValueException',
1,
], ],
'empty dates' => [ 'empty dates' => [
'', '',
'', '',
false false,
'UnexpectedValueException',
1
], ],
'invalid dates' => [ 'invalid dates' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date' => [
'1990-01-01',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
'out of bound dates' => [ 'out of bound dates' => [
'1900-1-1', '1900-1-1',
'9999-12-31', '9999-12-31',
-1 -1,
null,
null,
] ]
]; ];
} }
/**
* Undocumented function
*
* @return array<mixed>
*/
public function dateTimeCompareProvider(): array public function dateTimeCompareProvider(): array
{ {
return [ return [
@@ -355,51 +383,85 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal no timestamp' => [ 'dates equal no timestamp' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller no timestamp' => [ 'second date smaller no timestamp' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'date equal first time smaller' => [ 'date equal first time smaller' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
-1, -1,
null,
null,
], ],
'date equal time equal' => [ 'date equal time equal' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
0, 0,
null,
null,
], ],
'date equal second time smaller' => [ 'date equal second time smaller' => [
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
1, 1,
null,
null,
], ],
'valid date invalid time' => [ 'valid date invalid time' => [
'2020-12-12 13:99:13', '2020-12-12 13:99:13',
'2020-12-12 12:12:99', '2020-12-12 12:12:99',
false, false,
'UnexpectedValueException',
2
],
'valid date invalid end time' => [
'2020-12-12 13:12:13',
'2020-12-12 12:12:99',
false,
'UnexpectedValueException',
3
], ],
'invalid datetimes --' => [ 'invalid datetimes --' => [
'--', '--',
'--', '--',
false, false,
'UnexpectedValueException',
1
], ],
'empty datetimess' => [ 'empty datetimess' => [
'', '',
'', '',
false, false,
'UnexpectedValueException',
1
], ],
'invalid datetimes' => [ 'invalid date times' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date time' => [
'1990-01-01 12:12:12',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
]; ];
} }
@@ -614,10 +676,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a * @param string $input_a
* @param string $input_b * @param string $input_b
* @param int|bool $expected * @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void * @return void
*/ */
public function testCompareDate(string $input_a, string $input_b, $expected): void public function testCompareDate(
{ string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Combined\DateTime::compareDate($input_a, $input_b) \CoreLibs\Combined\DateTime::compareDate($input_a, $input_b)
@@ -634,10 +707,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a * @param string $input_a
* @param string $input_b * @param string $input_b
* @param int|bool $expected * @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void * @return void
*/ */
public function testCompareDateTime(string $input_a, string $input_b, $expected): void public function testCompareDateTime(
{ string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b) \CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b)

View File

@@ -59,6 +59,27 @@ final class CoreLibsConvertColorsTest extends TestCase
3 => false, 3 => false,
4 => false 4 => false
], ],
'invalid color red ' => [
0 => -12,
1 => 12,
2 => 12,
3 => false,
4 => false
],
'invalid color green ' => [
0 => 12,
1 => -12,
2 => 12,
3 => false,
4 => false
],
'invalid color blue ' => [
0 => 12,
1 => 12,
2 => -12,
3 => false,
4 => false
],
]; ];
} }
@@ -150,10 +171,40 @@ final class CoreLibsConvertColorsTest extends TestCase
'valid' => true, 'valid' => true,
], ],
// invalid values // invalid values
'invalid color' => [ 'invalid color r/h/h low' => [
'rgb' => [-12, 300, 12], 'rgb' => [-1, 12, 12],
'hsb' => [-12, 300, 12], 'hsb' => [-1, 50, 50],
'hsl' => [-12, 300, 12], 'hsl' => [-1, 50, 50],
'valid' => false,
],
'invalid color r/h/h high' => [
'rgb' => [256, 12, 12],
'hsb' => [361, 50, 50],
'hsl' => [361, 50, 50],
'valid' => false,
],
'invalid color g/s/s low' => [
'rgb' => [12, -1, 12],
'hsb' => [1, -1, 50],
'hsl' => [1, -1, 50],
'valid' => false,
],
'invalid color g/s/s high' => [
'rgb' => [12, 256, 12],
'hsb' => [1, 101, 50],
'hsl' => [1, 101, 50],
'valid' => false,
],
'invalid color b/b/l low' => [
'rgb' => [12, 12, -1],
'hsb' => [1, 50, -1],
'hsl' => [1, 50, -1],
'valid' => false,
],
'invalid color b/b/l high' => [
'rgb' => [12, 12, 256],
'hsb' => [1, 50, 101],
'hsl' => [1, 50, 101],
'valid' => false, 'valid' => false,
], ],
]; ];
@@ -246,11 +297,22 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param int $input_r * @param int $input_r
* @param int $input_g * @param int $input_g
* @param int $input_b * @param int $input_b
* @param string|bool $expected_hash
* @param string|bool $expected * @param string|bool $expected
* @return void * @return void
*/ */
public function testRgb2hex(int $input_r, int $input_g, int $input_b, $expected_hash, $expected) public function testRgb2hex(
{ int $input_r,
int $input_g,
int $input_b,
string|bool $expected_hash,
string|bool $expected
) {
// if expected hash is or expected is false, we need to check for
// LengthException
if ($expected_hash === false || $expected === false) {
$this->expectException(\LengthException::class);
}
// with # // with #
$this->assertEquals( $this->assertEquals(
$expected_hash, $expected_hash,
@@ -292,11 +354,19 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHex2rgb( public function testHex2rgb(
string $input, string $input,
$expected, array|bool $expected,
$expected_str, string|bool $expected_str,
string $separator, string $separator,
$expected_str_sep string|bool $expected_str_sep
): void { ): void {
if ($expected === false || $expected_str === false || $expected_str_sep === false) {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $input);
if (!is_string($hex_string)) {
$this->expectException(\InvalidArgumentException::class);
} else {
$this->expectException(\UnexpectedValueException::class);
}
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hex2rgb($input) \CoreLibs\Convert\Colors::hex2rgb($input)
@@ -324,8 +394,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsb(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b)
@@ -345,8 +418,12 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, $expected): void public function testHsb2rgb(float $input_h, float $input_s, float $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
$expected = [];
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b) \CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b)
@@ -366,8 +443,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsl(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b)
@@ -387,8 +467,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsl2rgb($input_h, float $input_s, float $input_l, $expected): void public function testHsl2rgb(int|float $input_h, float $input_s, float $input_l, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l) \CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l)
@@ -406,11 +489,11 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHslHsb360hue(): void public function testHslHsb360hue(): void
{ {
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2), \CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2),
'HSL to RGB with 360 hue' 'HSL to RGB with 360 hue'
); );
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0), \CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0),
'HSB to RGB with 360 hue' 'HSB to RGB with 360 hue'
); );

View File

@@ -16,7 +16,7 @@ final class CoreLibsConvertJsonTest extends TestCase
/** /**
* test list for json convert tests * test list for json convert tests
* *
* @return array * @return array<mixed>
*/ */
public function jsonProvider(): array public function jsonProvider(): array
{ {
@@ -54,10 +54,36 @@ final class CoreLibsConvertJsonTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @return array<mixed>
*/
public function jsonArrayProvider(): array
{
return [
'valid json' => [
[
'm' => 2,
'f' => 'sub_2'
],
'{"m":2,"f":"sub_2"}',
],
'empty json array' => [
[],
'[]'
],
'empty json hash' => [
['' => ''],
'{"":""}'
]
];
}
/** /**
* json error list * json error list
* *
* @return array JSON error list * @return array<mixed> JSON error list
*/ */
public function jsonErrorProvider(): array public function jsonErrorProvider(): array
{ {
@@ -127,7 +153,7 @@ final class CoreLibsConvertJsonTest extends TestCase
* *
* @param string|null $input * @param string|null $input
* @param bool $flag * @param bool $flag
* @param array $expected * @param array<mixed> $expected
* @return void * @return void
*/ */
public function testJsonConvertToArray(?string $input, bool $flag, array $expected): void public function testJsonConvertToArray(?string $input, bool $flag, array $expected): void
@@ -146,7 +172,8 @@ final class CoreLibsConvertJsonTest extends TestCase
* @testdox jsonGetLastError $input will be $expected_i/$expected_s [$_dataName] * @testdox jsonGetLastError $input will be $expected_i/$expected_s [$_dataName]
* *
* @param string|null $input * @param string|null $input
* @param string $expected * @param int $expected_i
* @param string $expected_s
* @return void * @return void
*/ */
public function testJsonGetLastError(?string $input, int $expected_i, string $expected_s): void public function testJsonGetLastError(?string $input, int $expected_i, string $expected_s): void
@@ -161,6 +188,25 @@ final class CoreLibsConvertJsonTest extends TestCase
\CoreLibs\Convert\Json::jsonGetLastError(true) \CoreLibs\Convert\Json::jsonGetLastError(true)
); );
} }
/**
* Undocumented function
*
* @covers ::jsonConvertArrayTo
* @dataProvider jsonArrayProvider
* @testdox jsonConvertArrayTo $input (Override: $flag) will be $expected [$_dataName]
*
* @param array<mixed> $input
* @param string $expected
* @return void
*/
public function testJsonConvertArrayto(array $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Json::jsonConvertArrayTo($input)
);
}
} }
// __END__ // __END__

View File

@@ -43,12 +43,17 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
null '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'not int' '1'
],
'array, override set' => [
[1, 2],
null,
null
] ]
]; ];
} }
@@ -201,7 +206,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
null 1
] ]
]; ];
} }
@@ -349,7 +354,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
null 1.0
] ]
]; ];
} }

View File

@@ -43,11 +43,16 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
'' '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'1'
],
'array, override set' => [
[1, 2],
'not int',
'not int' 'not int'
] ]
]; ];
@@ -189,7 +194,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
0 1
] ]
]; ];
} }
@@ -330,7 +335,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
0.0 1.0
] ]
]; ];
} }
@@ -341,7 +346,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
* @dataProvider varSetTypeFloatProvider * @dataProvider varSetTypeFloatProvider
* @testdox setFloat $input with override $default will be $expected [$_dataName] * @testdox setFloat $input with override $default will be $expected [$_dataName]
* *
* @param mixed $input * @param mixed $input
* @param float|null $default * @param float|null $default
* @param float $expected * @param float $expected
* @return void * @return void

View File

@@ -30,8 +30,10 @@ final class CoreLibsCreateSessionTest extends TestCase
// setSessionName: true/false, // setSessionName: true/false,
// checkActiveSession: true/false, [1st call, 2nd call] // checkActiveSession: true/false, [1st call, 2nd call]
// getSessionId: string or false // getSessionId: string or false
// 3: exepcted name (session) // 3: exepcted name (session)]
// 4: expected error string // 4: Exception thrown on error
// 5: exception code, null for none
// 6: expected error string
return [ return [
'session parameter' => [ 'session parameter' => [
'sessionNameParameter', 'sessionNameParameter',
@@ -44,7 +46,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameParameter', 'sessionNameParameter',
'' null,
null,
'',
], ],
'session globals' => [ 'session globals' => [
'sessionNameGlobals', 'sessionNameGlobals',
@@ -57,7 +61,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameGlobals', 'sessionNameGlobals',
'' null,
null,
'',
], ],
'session name default' => [ 'session name default' => [
'', '',
@@ -70,7 +76,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'' null,
null,
'',
], ],
// error checks // error checks
// 1: we are in cli // 1: we are in cli
@@ -85,6 +93,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
1,
'[SESSION] No sessions in php cli' '[SESSION] No sessions in php cli'
], ],
// 2: session disabled // 2: session disabled
@@ -99,6 +109,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
2,
'[SESSION] Sessions are disabled' '[SESSION] Sessions are disabled'
], ],
// 3: invalid session name: string // 3: invalid session name: string
@@ -113,6 +125,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 1invalid$session#;' '[SESSION] Invalid session name: 1invalid$session#;'
], ],
// 3: invalid session name: only numbers // 3: invalid session name: only numbers
@@ -127,6 +141,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 123' '[SESSION] Invalid session name: 123'
], ],
// 3: invalid session name: invalid name short // 3: invalid session name: invalid name short
@@ -143,6 +159,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
4,
'[SESSION] Failed to activate session' '[SESSION] Failed to activate session'
], ],
// 5: get session id return false // 5: get session id return false
@@ -157,6 +175,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => false 'getSessionId' => false
], ],
'', '',
'UnexpectedValueException',
5,
'[SESSION] getSessionId did not return a session id' '[SESSION] getSessionId did not return a session id'
], ],
]; ];
@@ -173,6 +193,7 @@ final class CoreLibsCreateSessionTest extends TestCase
* @param string $type * @param string $type
* @param array<mixed> $mock_data * @param array<mixed> $mock_data
* @param string $expected * @param string $expected
* @param string|null $exception
* @param string $expected_error * @param string $expected_error
* @return void * @return void
*/ */
@@ -181,6 +202,8 @@ final class CoreLibsCreateSessionTest extends TestCase
string $type, string $type,
array $mock_data, array $mock_data,
string $expected, string $expected,
?string $exception,
?int $exception_code,
string $expected_error string $expected_error
): void { ): void {
// override expected // override expected
@@ -224,6 +247,11 @@ final class CoreLibsCreateSessionTest extends TestCase
// regex for session id // regex for session id
$ression_id_regex = "/^\w+$/"; $ression_id_regex = "/^\w+$/";
if ($exception !== null) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
unset($GLOBALS['SET_SESSION_NAME']); unset($GLOBALS['SET_SESSION_NAME']);
$session_id = ''; $session_id = '';
switch ($type) { switch ($type) {
@@ -253,13 +281,6 @@ final class CoreLibsCreateSessionTest extends TestCase
$expected, $expected,
$session_mock->getSessionName() $session_mock->getSessionName()
); );
} else {
// false checks
$this->assertEquals(
$expected_error,
$session_mock->getErrorStr(),
'error assert'
);
} }
} }

View File

@@ -445,12 +445,14 @@ final class CoreLibsDBIOTest extends TestCase
{ {
// 0: connection array // 0: connection array
// 1: status after connection // 1: status after connection
// 2: exception name
// 2: info string // 2: info string
// 3: ??? // 3: ???
return [ return [
'invalid connection' => [ 'invalid connection' => [
self::$db_config['invalid'], self::$db_config['invalid'],
false, false,
'RuntimeException',
"-DB-info-> Connected to db '' with schema 'public' as user " "-DB-info-> Connected to db '' with schema 'public' as user "
. "'' at host '' on port '5432' with ssl mode 'allow' **** " . "'' at host '' on port '5432' with ssl mode 'allow' **** "
. "-DB-info-> DB IO Class debug output: Yes **** ", . "-DB-info-> DB IO Class debug output: Yes **** ",
@@ -459,6 +461,7 @@ final class CoreLibsDBIOTest extends TestCase
'valid connection' => [ 'valid connection' => [
self::$db_config['valid'], self::$db_config['valid'],
true, true,
'',
"-DB-info-> Connected to db 'corelibs_db_io_test' with " "-DB-info-> Connected to db 'corelibs_db_io_test' with "
. "schema 'public' as user 'corelibs_db_io_test' at host " . "schema 'public' as user 'corelibs_db_io_test' at host "
. "'localhost' on port '5432' with ssl mode 'allow' **** " . "'localhost' on port '5432' with ssl mode 'allow' **** "
@@ -475,13 +478,21 @@ final class CoreLibsDBIOTest extends TestCase
* @dataProvider connectionProvider * @dataProvider connectionProvider
* @testdox Connection will be $expected [$_dataName] * @testdox Connection will be $expected [$_dataName]
* *
* @param array $connection
* @param bool $expected_status
* @param string $exception
* @param string $expected_string
* @return void * @return void
*/ */
public function testConnection( public function testConnection(
array $connection, array $connection,
bool $expected_status, bool $expected_status,
string $exception,
string $expected_string string $expected_string
): void { ): void {
if ($expected_status === false) {
$this->expectException($exception);
}
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
$connection, $connection,
self::$log self::$log
@@ -722,6 +733,10 @@ final class CoreLibsDBIOTest extends TestCase
*/ */
public function testGetSetting(string $connection, array $settings): void public function testGetSetting(string $connection, array $settings): void
{ {
// if settings are all empty -> assume exception
if (empty($settings['db_name']) && empty($settings['db_user'])) {
$this->expectException('RuntimeException');
}
$db = new \CoreLibs\DB\IO( $db = new \CoreLibs\DB\IO(
self::$db_config[$connection], self::$db_config[$connection],
self::$log self::$log

View File

@@ -562,10 +562,10 @@ final class CoreLibsDebugSupportTest extends TestCase
} }
/** /**
* Undocumented function * test the lowest one (one above base)
* *
* @cover ::getCallerClass * @cover ::getCallerClass
* @testWith ["PHPUnit\\TextUI\\Command"] * @testWith ["tests\\CoreLibsDebugSupportTest"]
* @testdox getCallerClass check if it returns $expected [$_dataName] * @testdox getCallerClass check if it returns $expected [$_dataName]
* *
* @return void * @return void
@@ -578,6 +578,40 @@ final class CoreLibsDebugSupportTest extends TestCase
); );
} }
/**
* test highest return (top level)
*
* @cover ::getCallerTopLevelClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testdox getCallerTopLevelClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerTopLevelClass(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerTopLevelClass()
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerClassMethod
* @testWith ["tests\\CoreLibsDebugSupportTest->testGetCallerClassMethod"]
* @testdox getCallerClassMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClassMethod(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerClassMethod()
);
}
/** /**
* Undocumented function * Undocumented function
* *

View File

@@ -0,0 +1,284 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Logging\Logger\Level;
/**
* Test class for Logging
* @coversDefaultClass \CoreLibs\Logging\ErrorMessages
* @testdox \CoreLibs\Logging\ErrorMEssages method tests
*/
final class CoreLibsLoggingErrorMessagesTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
/**
* tear down and remove log data
*
* @return void
*/
public static function tearDownAfterClass(): void
{
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
}
/**
* for checking level only
*
* @return array
*/
public function providerErrorMessageLevel(): array
{
return [
'ok' => [
'level' => 'ok',
'str' => 'OK',
'expected' => 'ok',
],
'info' => [
'level' => 'info',
'str' => 'INFO',
'expected' => 'info',
],
'warn' => [
'level' => 'warn',
'str' => 'WARN',
'expected' => 'warn'
],
'warning' => [
'level' => 'warning',
'str' => 'WARN',
'expected' => 'warn'
],
'error' => [
'level' => 'error',
'str' => 'ERROR',
'expected' => 'error'
],
'abort' => [
'level' => 'abort',
'str' => 'ABORT',
'expected' => 'abort'
],
'crash' => [
'level' => 'crash',
'str' => 'CRASH',
'expected' => 'crash'
],
'wrong level' => [
'level' => 'wrong',
'str' => 'WRONG',
'expected' => 'unknown'
]
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLevel
* @testdox error message level: $level will be $expected [$_dataName]
*
* @param string $level
* @param string $str
* @param string $expected
* @return void
*/
public function testErrorMessageLevelOk(string $level, string $str, string $expected): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsgLevel(
$level,
$str
);
$this->assertEquals(
[
'level' => $expected,
'str' => $str,
'id' => '',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
}
/**
* Undocumented function
*
* @testdox Test of all methods for n messages [$_dataName]
*
* @return void
*/
public function testErrorMessageOk(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
'100',
'info',
'INFO MESSAGE'
);
$this->assertEquals(
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
$em->setErrorMsg(
'200',
'error',
'ERROR MESSAGE'
);
$this->assertEquals(
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100', '200'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
}
public function providerErrorMessageLog(): array
{
return [
'crash' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => null,
'expected' => '<ALERT> CRASH MESSAGE',
],
'crash, message' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => 'OTHER CRASH MESSAGE',
'expected' => '<ALERT> OTHER CRASH MESSAGE',
],
'abort' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => null,
'expected' => '<CRITICAL> ABORT MESSAGE',
],
'abort, message' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => 'OTHER ABORT MESSAGE',
'expected' => '<CRITICAL> OTHER ABORT MESSAGE',
],
'unknown' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => null,
'expected' => '<EMERGENCY> WRONG LEVEL MESSAGE',
],
'unknown, message' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => 'OTHER WRONG LEVEL MESSAGE',
'expected' => '<EMERGENCY> OTHER WRONG LEVEL MESSAGE',
],
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLog
* @testdox Test Log writing [$_dataName]
*
* @return void
*/
public function testErrorMessageLog(string $id, string $level, string $str, ?string $message, string $expected)
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
$level,
$str,
message: $message
);
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
$this->assertStringContainsString(
$expected,
$file_content
);
}
}
// __END__

View File

@@ -22,7 +22,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port . "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
. "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file . "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file
. "\[\w+\]\s{1}" // run id . "\[\w+\]\s{1}" // run id
. "{[\w\\\\]+(::\w+)?}\s{1}"; // class . "{[\w\\\\]+((::|->)\w+)?}\s{1}"; // class
public static function tearDownAfterClass(): void public static function tearDownAfterClass(): void
{ {