diff --git a/www/composer.lock b/www/composer.lock index 170b44d1..6f0b15b4 100644 --- a/www/composer.lock +++ b/www/composer.lock @@ -8,11 +8,11 @@ "packages": [ { "name": "egrajp/corelibs-composer-all", - "version": "dev-development", + "version": "dev-master", "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "e318a4fb9a5a34894e2fbff2f110c6626c87be0e" + "reference": "bcc1e833c12b8c39a48e9209502e6c2b5742423d" }, "require": { "php": ">=8.2", @@ -22,7 +22,9 @@ "egrajp/smarty-extended": "^4.3", "gullevek/dotenv": "dev-master", "phan/phan": "^5.4", - "phpstan/phpstan": "^1.12", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", "phpunit/phpunit": "^9" }, "type": "library", @@ -78,16 +80,16 @@ }, { "name": "gullevek/dotenv", - "version": "v2.1.0", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/gullevek/dotEnv.git", - "reference": "b9feacaded4e48effff9da7d1173752aef3dc27f" + "reference": "a7ade8648594c937ca24adb758eb5a702529cf70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gullevek/dotEnv/zipball/b9feacaded4e48effff9da7d1173752aef3dc27f", - "reference": "b9feacaded4e48effff9da7d1173752aef3dc27f", + "url": "https://api.github.com/repos/gullevek/dotEnv/zipball/a7ade8648594c937ca24adb758eb5a702529cf70", + "reference": "a7ade8648594c937ca24adb758eb5a702529cf70", "shasum": "" }, "require": { @@ -95,7 +97,9 @@ }, "require-dev": { "phan/phan": "^5.4", - "phpstan/phpstan": "^1.10", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", "phpunit/phpunit": "^9" }, "type": "library", @@ -126,9 +130,9 @@ ], "support": { "issues": "https://github.com/gullevek/dotEnv/issues", - "source": "https://github.com/gullevek/dotEnv/tree/v2.1.0" + "source": "https://github.com/gullevek/dotEnv/tree/v2.1.1" }, - "time": "2024-08-21T02:41:15+00:00" + "time": "2024-11-18T11:10:09+00:00" }, { "name": "psr/log", diff --git a/www/vendor/composer/installed.json b/www/vendor/composer/installed.json index 3a993cb6..8b720287 100644 --- a/www/vendor/composer/installed.json +++ b/www/vendor/composer/installed.json @@ -2,12 +2,12 @@ "packages": [ { "name": "egrajp/corelibs-composer-all", - "version": "dev-development", - "version_normalized": "dev-development", + "version": "dev-master", + "version_normalized": "dev-master", "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "e318a4fb9a5a34894e2fbff2f110c6626c87be0e" + "reference": "bcc1e833c12b8c39a48e9209502e6c2b5742423d" }, "require": { "php": ">=8.2", @@ -17,7 +17,9 @@ "egrajp/smarty-extended": "^4.3", "gullevek/dotenv": "dev-master", "phan/phan": "^5.4", - "phpstan/phpstan": "^1.12", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", "phpunit/phpunit": "^9" }, "type": "library", @@ -78,17 +80,17 @@ }, { "name": "gullevek/dotenv", - "version": "v2.1.0", - "version_normalized": "2.1.0.0", + "version": "v2.1.1", + "version_normalized": "2.1.1.0", "source": { "type": "git", "url": "https://github.com/gullevek/dotEnv.git", - "reference": "b9feacaded4e48effff9da7d1173752aef3dc27f" + "reference": "a7ade8648594c937ca24adb758eb5a702529cf70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gullevek/dotEnv/zipball/b9feacaded4e48effff9da7d1173752aef3dc27f", - "reference": "b9feacaded4e48effff9da7d1173752aef3dc27f", + "url": "https://api.github.com/repos/gullevek/dotEnv/zipball/a7ade8648594c937ca24adb758eb5a702529cf70", + "reference": "a7ade8648594c937ca24adb758eb5a702529cf70", "shasum": "" }, "require": { @@ -96,10 +98,12 @@ }, "require-dev": { "phan/phan": "^5.4", - "phpstan/phpstan": "^1.10", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", "phpunit/phpunit": "^9" }, - "time": "2024-08-21T02:41:15+00:00", + "time": "2024-11-18T11:10:09+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -129,7 +133,7 @@ ], "support": { "issues": "https://github.com/gullevek/dotEnv/issues", - "source": "https://github.com/gullevek/dotEnv/tree/v2.1.0" + "source": "https://github.com/gullevek/dotEnv/tree/v2.1.1" }, "install-path": "../gullevek/dotenv" }, diff --git a/www/vendor/composer/installed.php b/www/vendor/composer/installed.php index 4c8ae232..2b204905 100644 --- a/www/vendor/composer/installed.php +++ b/www/vendor/composer/installed.php @@ -11,9 +11,9 @@ ), 'versions' => array( 'egrajp/corelibs-composer-all' => array( - 'pretty_version' => 'dev-development', - 'version' => 'dev-development', - 'reference' => 'e318a4fb9a5a34894e2fbff2f110c6626c87be0e', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'bcc1e833c12b8c39a48e9209502e6c2b5742423d', 'type' => 'library', 'install_path' => __DIR__ . '/../egrajp/corelibs-composer-all', 'aliases' => array(), @@ -38,9 +38,9 @@ 'dev_requirement' => false, ), 'gullevek/dotenv' => array( - 'pretty_version' => 'v2.1.0', - 'version' => '2.1.0.0', - 'reference' => 'b9feacaded4e48effff9da7d1173752aef3dc27f', + 'pretty_version' => 'v2.1.1', + 'version' => '2.1.1.0', + 'reference' => 'a7ade8648594c937ca24adb758eb5a702529cf70', 'type' => 'library', 'install_path' => __DIR__ . '/../gullevek/dotenv', 'aliases' => array(), diff --git a/www/vendor/egrajp/corelibs-composer-all/composer.json b/www/vendor/egrajp/corelibs-composer-all/composer.json index f5d9ec12..3bb2b07d 100644 --- a/www/vendor/egrajp/corelibs-composer-all/composer.json +++ b/www/vendor/egrajp/corelibs-composer-all/composer.json @@ -20,7 +20,9 @@ "psr/log": "^3.0@dev" }, "require-dev": { - "phpstan/phpstan": "^1.12", + "phpstan/phpstan": "^2.0", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", "phan/phan": "^5.4", "egrajp/smarty-extended": "^4.3", "gullevek/dotenv": "dev-master", diff --git a/www/vendor/egrajp/corelibs-composer-all/publish/last.published b/www/vendor/egrajp/corelibs-composer-all/publish/last.published index eea47571..139aee8b 100644 --- a/www/vendor/egrajp/corelibs-composer-all/publish/last.published +++ b/www/vendor/egrajp/corelibs-composer-all/publish/last.published @@ -1 +1 @@ -9.18.1 +9.20.0 diff --git a/www/vendor/egrajp/corelibs-composer-all/src/ACL/Login.php b/www/vendor/egrajp/corelibs-composer-all/src/ACL/Login.php index 2a38c219..2ed56c09 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/ACL/Login.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/ACL/Login.php @@ -960,10 +960,7 @@ class Login . "AND ear.edit_access_right_id = epa.edit_access_right_id " . "AND epa.enabled = 1 AND epa.edit_group_id = " . $res["edit_group_id"] . " " . "ORDER BY ep.order_number"; - while ($res = $this->db->dbReturn($q)) { - if (!is_array($res)) { - break; - } + while (is_array($res = $this->db->dbReturn($q))) { // page id array for sub data readout $edit_page_ids[$res['edit_page_id']] = $res['cuid']; // create the array for pages @@ -1303,11 +1300,9 @@ class Login { $is_valid_password = true; // check for valid in regex arrays in list - if (is_array($this->password_valid_chars)) { - foreach ($this->password_valid_chars as $password_valid_chars) { - if (!preg_match("/$password_valid_chars/", $password)) { - $is_valid_password = false; - } + foreach ($this->password_valid_chars as $password_valid_chars) { + if (!preg_match("/$password_valid_chars/", $password)) { + $is_valid_password = false; } } // check for min length diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Admin/Backend.php b/www/vendor/egrajp/corelibs-composer-all/src/Admin/Backend.php index 9f705c7b..5fb2918b 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Admin/Backend.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Admin/Backend.php @@ -425,10 +425,7 @@ class Backend ?string $set_content_path = null, int $flag = 0, ): array { - if ( - $set_content_path === null || - !is_string($set_content_path) - ) { + if ($set_content_path === null) { /** @deprecated adbTopMenu missing set_content_path parameter */ trigger_error( 'Calling adbTopMenu without set_content_path parameter is deprecated', diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Check/Colors.php b/www/vendor/egrajp/corelibs-composer-all/src/Check/Colors.php index d896664a..8630dd12 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Check/Colors.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Check/Colors.php @@ -119,6 +119,13 @@ class Colors /** * check if html/css color string is valid + * + * TODO: update check for correct validate values + * - space instead of "," + * - / opcatiy checks + * - loose numeric values + * - lab/lch,oklab/oklch validation too + * * @param string $color A color string of any format * @param int $flags defaults to ALL, else use | to combined from * HEX_RGB, HEX_RGBA, RGB, RGBA, HSL, HSLA @@ -168,9 +175,9 @@ class Colors if (preg_match("/$regex/", $color)) { // if valid regex, we now need to check if the content is actually valid // only for rgb/hsl type - /** @var int|false */ + /** @var int<0, max>|false */ $rgb_flag = strpos($color, 'rgb'); - /** @var int|false */ + /** @var int<0, max>|false */ $hsl_flag = strpos($color, 'hsl'); // if both not match, return true if ( diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Convert/Math.php b/www/vendor/egrajp/corelibs-composer-all/src/Convert/Math.php index 41eb7463..daf4bf07 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Convert/Math.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Convert/Math.php @@ -158,6 +158,8 @@ class Math * [0, 0, 0] <- automatically added * ] * + * The same is done for unbalanced entries, they are filled with 0 + * * @param array> $a m x n matrice * @param array> $b n x p matrice * @@ -186,7 +188,7 @@ class Math // so that we can multiply row by row $bCols = array_map( callback: fn ($k) => array_map( - (fn ($i) => is_array($i) ? $i[$k] : 0), + (fn ($i) => is_array($i) ? $i[$k] ?? 0 : 0), $b, ), array: array_keys($b[0]), diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Create/Uids.php b/www/vendor/egrajp/corelibs-composer-all/src/Create/Uids.php index 47691338..42339797 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Create/Uids.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Create/Uids.php @@ -38,7 +38,7 @@ class Uids $uniqid_length++; } /** @var int<1,max> make sure that internal this is correct */ - $random_bytes_length = ($uniqid_length - ($uniqid_length % 2)) / 2; + $random_bytes_length = (int)(($uniqid_length - ($uniqid_length % 2)) / 2); $uniqid = bin2hex(random_bytes($random_bytes_length)); // if not forced shorten return next lower length if (!$force_length) { diff --git a/www/vendor/egrajp/corelibs-composer-all/src/DB/Extended/ArrayIO.php b/www/vendor/egrajp/corelibs-composer-all/src/DB/Extended/ArrayIO.php index d40b71b4..ac98091c 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/DB/Extended/ArrayIO.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/DB/Extended/ArrayIO.php @@ -374,7 +374,7 @@ class ArrayIO extends \CoreLibs\DB\IO public function dbDelete(array $table_array = [], bool $acl_limit = false): array { // is array and has values, override set and set new - if (is_array($table_array) && count($table_array)) { + if (count($table_array)) { $this->table_array = $table_array; } if (!$this->dbCheckPkSet()) { @@ -440,7 +440,7 @@ class ArrayIO extends \CoreLibs\DB\IO public function dbRead(bool $edit = false, array $table_array = []): array { // if array give, overrules internal array - if (is_array($table_array) && count($table_array)) { + if (count($table_array)) { $this->table_array = $table_array; } if (!$this->dbCheckPkSet()) { diff --git a/www/vendor/egrajp/corelibs-composer-all/src/DB/IO.php b/www/vendor/egrajp/corelibs-composer-all/src/DB/IO.php index d3ecc374..4daad5b8 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/DB/IO.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/DB/IO.php @@ -284,7 +284,8 @@ class IO public const ERROR_HASH_TYPE = 'adler32'; /** @var string regex to get returning with matches at position 1 */ public const REGEX_RETURNING = '/\s+returning\s+(.+\s*(?:.+\s*)+);?$/i'; - /** @var array allowed convert target for placeholder: pg or pdo (currently not available) */ + /** @var array allowed convert target for placeholder: + * pg or pdo (currently not available) */ public const DB_CONVERT_PLACEHOLDER_TARGET = ['pg']; // REGEX_SELECT // REGEX_UPDATE @@ -914,7 +915,7 @@ class IO if ($cursor !== false) { [$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError($cursor); } - if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) { + if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) { /** @phpstan-ignore-line */ [$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError(); } // prefix the master if not the same @@ -1311,33 +1312,14 @@ class IO } /** - * count $ leading parameters only + * count placeholder entries in the query * * @param string $query Query to check * @return int Number of parameters found */ private function __dbCountQueryParams(string $query): int { - $match = []; - // regex for params: only stand alone $number allowed - // exclude all '' enclosed strings, ignore all numbers [note must start with digit] - // can have space/tab/new line - // must have <> = , ( [not equal, equal, comma, opening round bracket] - // can have space/tab/new line - // $ number with 1-9 for first and 0-9 for further digits - // /s for matching new line in . list - // [disabled, we don't used ^ or $] /m for multi line match - // Matches in 1:, must be array_filtered to remove empty, count with array_unique - $query_split = '[(=,?-]|->|->>|#>|#>>|@>|<@|\?\|\?\&|\|\||#-'; - preg_match_all( - '/' - . '(?:\'.*?\')?\s*(?:\?\?|<>|' . $query_split . ')\s*' - . '(?:\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))' - . '/s', - $query, - $match - ); - return count(array_unique(array_filter($match[1]))); + return $this->db_functions->__dbCountQueryParams($query); } /** @@ -1737,7 +1719,7 @@ class IO { if ( !empty($this->dbh) && - $this->dbh instanceof \PgSql\Connection + $this->dbh instanceof \PgSql\Connection /** @phpstan-ignore-line future could be other */ ) { // reset any client encodings set $this->dbResetEncoding(); @@ -3160,7 +3142,8 @@ class IO 'count' => 0, 'query' => '', 'result' => null, - 'returning_id' => false + 'returning_id' => false, + 'placeholder_converted' => [], ]; // if this is an insert query, check if we can add a return if ($this->dbCheckQueryForInsert($query, true)) { @@ -3200,6 +3183,39 @@ class IO $this->prepare_cursor[$stm_name]['pk_name'] = $pk_name; } } + // QUERY PARAMS: run query params check and rewrite + if ($this->dbGetConvertPlaceholder() === true) { + try { + $this->placeholder_converted = ConvertPlaceholder::convertPlaceholderInQuery( + $query, + null, + $this->dbGetConvertPlaceholderTarget() + ); + // write the new queries over the old + if (!empty($this->placeholder_converted['query'])) { + $query = $this->placeholder_converted['query']; + } + $this->prepare_cursor[$stm_name]['placeholder_converted'] = $this->placeholder_converted; + } catch (\OutOfRangeException $e) { + $this->__dbError($e->getCode(), context:[ + 'statement_name' => $stm_name, + 'query' => $query, + 'location' => 'dbPrepare', + 'error' => 'OutOfRangeException', + 'exception' => $e + ]); + return false; + } catch (\RuntimeException $e) { + $this->__dbError($e->getCode(), context:[ + 'statement_name' => $stm_name, + 'query' => $query, + 'location' => 'dbPrepare', + 'error' => 'RuntimeException', + 'exception' => $e + ]); + return false; + } + } // check prepared curser parameter count $this->prepare_cursor[$stm_name]['count'] = $this->__dbCountQueryParams($query); $this->prepare_cursor[$stm_name]['query'] = $query; @@ -3735,7 +3751,7 @@ class IO } /** - * convert db values (set) + * convert db values (set) to php matching types * * @param Convert $convert * @return void @@ -3746,7 +3762,7 @@ class IO } /** - * unsert convert db values flag + * unsert convert db values flag for converting db to php matching types * * @param Convert $convert * @return void @@ -3757,7 +3773,7 @@ class IO } /** - * Reset to origincal config file set + * Reset to original config file set for converting db to php matching type * * @return void */ @@ -3769,7 +3785,7 @@ class IO } /** - * check if a conert flag is set + * check if a convert flag is set for converting db to php matching type * * @param Convert $convert * @return bool @@ -3783,7 +3799,7 @@ class IO } /** - * Set if we want to auto convert PDO/\Pg placeholders + * Set if we want to auto convert to PDO/\Pg placeholders * * @param bool $flag * @return void @@ -4294,7 +4310,7 @@ class IO * @param string $stm_name The name of the stored statement * @param string $key Key field name in prepared cursor array * Allowed are: pk_name, count, query, returning_id - * @return null|string|int|bool Entry from each of the valid keys + * @return null|string|int|bool|array Entry from each of the valid keys * Will return false on error * Not ethat returnin_id also can return false * but will not set an error entry @@ -4302,7 +4318,7 @@ class IO public function dbGetPrepareCursorValue( string $stm_name, string $key - ): null|string|int|bool { + ): null|string|int|bool|array { // if no statement name if (empty($stm_name)) { $this->__dbError( @@ -4313,7 +4329,7 @@ class IO return false; } // if not a valid key - if (!in_array($key, ['pk_name', 'count', 'query', 'returning_id'])) { + if (!in_array($key, ['pk_name', 'count', 'query', 'returning_id', 'placeholder_converted'])) { $this->__dbError( 102, false, diff --git a/www/vendor/egrajp/corelibs-composer-all/src/DB/SQL/PgSQL.php b/www/vendor/egrajp/corelibs-composer-all/src/DB/SQL/PgSQL.php index fa4c7e89..53b97250 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/DB/SQL/PgSQL.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/DB/SQL/PgSQL.php @@ -51,6 +51,8 @@ declare(strict_types=1); namespace CoreLibs\DB\SQL; +use CoreLibs\DB\Support\ConvertPlaceholder; + // below no ignore is needed if we want to use PgSql interface checks with PHP 8.0 // as main system. Currently all @var sets are written as object /** @#phan-file-suppress PhanUndeclaredTypeProperty,PhanUndeclaredTypeParameter,PhanUndeclaredTypeReturnType */ @@ -102,7 +104,7 @@ class PgSQL implements Interface\SqlFunctions * SELECT foo FROM bar WHERE foobar = $1 * * @param string $query Query string with placeholders $1, .. - * @param array $params Matching parameters for each placerhold + * @param array $params Matching parameters for each placeholder * @return \PgSql\Result|false Query result */ public function __dbQueryParams(string $query, array $params): \PgSql\Result|false @@ -140,7 +142,7 @@ class PgSQL implements Interface\SqlFunctions * sends an async query to the server with params * * @param string $query Query string with placeholders $1, .. - * @param array $params Matching parameters for each placerhold + * @param array $params Matching parameters for each placeholder * @return bool true/false Query sent successful status */ public function __dbSendQueryParams(string $query, array $params): bool @@ -966,6 +968,34 @@ class PgSQL implements Interface\SqlFunctions { return $this->__dbShow('client_encoding'); } + + /** + * Count placeholder queries. $ only + * + * @param string $query + * @return int + */ + public function __dbCountQueryParams(string $query): int + { + $matches = []; + // regex for params: only stand alone $number allowed + // exclude all '' enclosed strings, ignore all numbers [note must start with digit] + // can have space/tab/new line + // must have <> = , ( [not equal, equal, comma, opening round bracket] + // can have space/tab/new line + // $ number with 1-9 for first and 0-9 for further digits + // Collects also PDO ? and :named, but they are ignored + // /s for matching new line in . list + // [disabled, we don't used ^ or $] /m for multi line match + // Matches in 1:, must be array_filtered to remove empty, count with array_unique + // Regex located in the ConvertPlaceholder class + preg_match_all( + ConvertPlaceholder::REGEX_LOOKUP_PLACEHOLDERS, + $query, + $matches + ); + return count(array_unique(array_filter($matches[3]))); + } } // __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/DB/Support/ConvertPlaceholder.php b/www/vendor/egrajp/corelibs-composer-all/src/DB/Support/ConvertPlaceholder.php index 6e652acc..0b9542b2 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/DB/Support/ConvertPlaceholder.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/DB/Support/ConvertPlaceholder.php @@ -14,6 +14,67 @@ namespace CoreLibs\DB\Support; class ConvertPlaceholder { + /** @var string split regex */ + private const PATTERN_QUERY_SPLIT = '[(<>=,?-]|->|->>|#>|#>>|@>|<@|\?\|\?\&|\|\||#-'; + /** @var string the main regex including the pattern query split */ + private const PATTERN_ELEMENT = '(?:\'.*?\')?\s*(?:\?\?|' . self::PATTERN_QUERY_SPLIT . ')\s*'; + /** @var string parts to ignore in the SQL */ + private const PATTERN_IGNORE = + // digit -> ignore + '\d+|' + // other string -> ignore + . '(?:\'.*?\')|'; + /** @var string named parameters */ + private const PATTERN_NAMED = '(:\w+)'; + /** @var string question mark parameters */ + private const PATTERN_QUESTION_MARK = '(?:(?:\?\?)?\s*(\?{1}))'; + /** @var string numbered parameters */ + private const PATTERN_NUMBERED = '(\$[1-9]{1}(?:[0-9]{1,})?)'; + // below here are full regex that will be used + /** @var string replace regex for named (:...) entries */ + public const REGEX_REPLACE_NAMED = '/' + . '(' . self::PATTERN_ELEMENT . ')' + . '(' + . self::PATTERN_IGNORE + . self::PATTERN_NAMED + . ')' + . '/s'; + /** @var string replace regex for question mark (?) entries */ + public const REGEX_REPLACE_QUESTION_MARK = '/' + . '(' . self::PATTERN_ELEMENT . ')' + . '(' + . self::PATTERN_IGNORE + . self::PATTERN_QUESTION_MARK + . ')' + . '/s'; + /** @var string replace regex for numbered ($n) entries */ + public const REGEX_REPLACE_NUMBERED = '/' + . '(' . self::PATTERN_ELEMENT . ')' + . '(' + . self::PATTERN_IGNORE + . self::PATTERN_NUMBERED + . ')' + . '/s'; + /** @var string the main lookup query for all placeholders */ + public const REGEX_LOOKUP_PLACEHOLDERS = '/' + // prefix string part, must match towards + // seperator for ( = , ? - [and json/jsonb in pg doc section 9.15] + . self::PATTERN_ELEMENT + // match for replace part + . '(?:' + // ignore parts + . self::PATTERN_IGNORE + // :name named part (PDO) [1] + . self::PATTERN_NAMED . '|' + // ? question mark part (PDO) [2] + . self::PATTERN_QUESTION_MARK . '|' + // $n numbered part (\PG php) [3] + . self::PATTERN_NUMBERED + // end match + . ')' + // single line -> add line break to matches in "." + . '/s'; + /** * Convert PDO type query with placeholders to \PG style and vica versa * For PDO to: ? and :named @@ -27,44 +88,24 @@ class ConvertPlaceholder * found has -1 if an error occoured in the preg_match_all call * * @param string $query Query with placeholders to convert - * @param array $params The parameters that are used for the query, and will be updated + * @param ?array $params The parameters that are used for the query, and will be updated * @param string $convert_to Either pdo or pg, will be converted to lower case for check - * @return array{original:array{query:string,params:array},type:''|'named'|'numbered'|'question_mark',found:int,matches:array,params_lookup:array,query:string,params:array} - * @throws \OutOfRangeException 200 + * @return array{original:array{query:string,params:array,empty_params:bool},type:''|'named'|'numbered'|'question_mark',found:int,matches:array,params_lookup:array,query:string,params:array} + * @throws \OutOfRangeException 200 If mixed placeholder types + * @throws \InvalidArgumentException 300 or 301 if wrong convert to with found placeholders */ public static function convertPlaceholderInQuery( string $query, - array $params, + ?array $params, string $convert_to = 'pg' ): array { $convert_to = strtolower($convert_to); $matches = []; - $query_split = '[(=,?-]|->|->>|#>|#>>|@>|<@|\?\|\?\&|\|\||#-'; - $pattern = '/' - // prefix string part, must match towards - // seperator for ( = , ? - [and json/jsonb in pg doc section 9.15] - . '(?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*' - // match for replace part - . '(?:' - // digit -> ignore - . '\d+|' - // other string -> ignore - . '(?:\'.*?\')|' - // :name named part (PDO) - . '(:\w+)|' - // ? question mark part (PDO) - . '(?:(?:\?\?)?\s*(\?{1}))|' - // $n numbered part (\PG php) - . '(\$[1-9]{1}(?:[0-9]{1,})?)' - // end match - . ')' - // single line -> add line break to matches in "." - . '/s'; // matches: // 1: :named // 2: ? question mark // 3: $n numbered - $found = preg_match_all($pattern, $query, $matches, PREG_UNMATCHED_AS_NULL); + $found = preg_match_all(self::REGEX_LOOKUP_PLACEHOLDERS, $query, $matches, PREG_UNMATCHED_AS_NULL); // if false or null set to -1 // || $found === null if ($found === false) { @@ -77,10 +118,10 @@ class ConvertPlaceholder /** @var array 3: $n matches */ $numbered_matches = array_filter($matches[3]); // count matches - $count_named = count($named_matches); + $count_named = count(array_unique($named_matches)); $count_qmark = count($qmark_matches); - $count_numbered = count($numbered_matches); - // throw if mixed + $count_numbered = count(array_unique($numbered_matches)); + // throw exception if mixed found if ( ($count_named && $count_qmark) || ($count_named && $count_numbered) || @@ -88,140 +129,195 @@ class ConvertPlaceholder ) { throw new \OutOfRangeException('Cannot have named, question mark and numbered in the same query', 200); } - // rebuild - $matches_return = []; - $type = ''; + // // throw if invalid conversion + // if (($count_named || $count_qmark) && $convert_to != 'pg') { + // throw new \InvalidArgumentException('Cannot convert from named or question mark placeholders to PDO', 300); + // } + // if ($count_numbered && $convert_to != 'pdo') { + // throw new \InvalidArgumentException('Cannot convert from numbered placeholders to Pg', 301); + // } + // return array + $return_placeholders = [ + // original + 'original' => [ + 'query' => $query, + 'params' => $params ?? [], + 'empty_params' => $params === null ? true : false, + ], + // type found, empty if nothing was done + 'type' => '', + // int: found, not found; -1: problem (set from false) + 'found' => (int)$found, + 'matches' => [], + // old to new lookup check + 'params_lookup' => [], + // this must match the count in params in new + 'needed' => 0, + // new + 'query' => '', + 'params' => [], + ]; + // replace basic regex and name settings + if ($count_named) { + $return_placeholders['type'] = 'named'; + $return_placeholders['matches'] = $named_matches; + $return_placeholders['needed'] = $count_named; + } elseif ($count_qmark) { + $return_placeholders['type'] = 'question_mark'; + $return_placeholders['matches'] = $qmark_matches; + $return_placeholders['needed'] = $count_qmark; + // for each ?:DTN: -> replace with $1 ... $n, any remaining :DTN: remove + } elseif ($count_numbered) { + $return_placeholders['type'] = 'numbered'; + $return_placeholders['matches'] = $numbered_matches; + $return_placeholders['needed'] = $count_numbered; + } + // run convert only if matching type and direction + if ( + (($count_named || $count_qmark) && $convert_to == 'pg') || + ($count_numbered && $convert_to == 'pdo') + ) { + $param_list = self::updateParamList($return_placeholders); + $return_placeholders['params_lookup'] = $param_list['params_lookup']; + $return_placeholders['query'] = $param_list['query']; + $return_placeholders['params'] = $param_list['params']; + } + // return data + return $return_placeholders; + } + + /** + * Updates the params list from one style to the other to match the query output + * if original.empty_params is set to true, no params replacement is done + * if param replacement has been done in a dbPrepare then this has to be run + * with the return palceholders array with params in original filled and empty_params turned off + * + * phpcs:disable Generic.Files.LineLength + * @param array{original:array{query:string,params:array,empty_params:bool},type:''|'named'|'numbered'|'question_mark',found:int,matches?:array,params_lookup?:array,query?:string,params?:array} $converted_placeholders + * phpcs:enable Generic.Files.LineLength + * @return array{params_lookup:array,query:string,params:array} + */ + public static function updateParamList(array $converted_placeholders): array + { + // skip if nothing set + if (!$converted_placeholders['found']) { + return [ + 'params_lookup' => [], + 'query' => '', + 'params' => [] + ]; + } $query_new = ''; $params_new = []; $params_lookup = []; - if ($count_named && $convert_to == 'pg') { - $type = 'named'; - $matches_return = $named_matches; - // only check for :named - $pattern_replace = '/' - . '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)' - . '(\d+|(?:\'.*?\')|(:\w+))' - . '/s'; - // 0: full - // 1: pre part - // 2: keep part UNLESS '3' is set - // 3: replace part :named - $pos = 0; - $query_new = preg_replace_callback( - $pattern_replace, - function ($matches) use (&$pos, &$params_new, &$params_lookup, $params) { - // only count up if $match[3] is not yet in lookup table - if (!empty($matches[3]) && empty($params_lookup[$matches[3]])) { - $pos++; - $params_lookup[$matches[3]] = '$' . $pos; - $params_new[] = $params[$matches[3]] ?? - throw new \RuntimeException( - 'Cannot lookup ' . $matches[3] . ' in params list', - 210 - ); - } - // add the connectors back (1), and the data sets only if no replacement will be done - return $matches[1] . ( - empty($matches[3]) ? - $matches[2] : - $params_lookup[$matches[3]] ?? + // set to null if params is empty + $params = $converted_placeholders['original']['params']; + $empty_params = $converted_placeholders['original']['empty_params']; + switch ($converted_placeholders['type']) { + case 'named': + // 0: full + // 0: full + // 1: pre part + // 2: keep part UNLESS '3' is set + // 3: replace part :named + $pos = 0; + $query_new = preg_replace_callback( + self::REGEX_REPLACE_NAMED, + function ($matches) use (&$pos, &$params_new, &$params_lookup, $params, $empty_params) { + // only count up if $match[3] is not yet in lookup table + if (!empty($matches[3]) && empty($params_lookup[$matches[3]])) { + $pos++; + $params_lookup[$matches[3]] = '$' . $pos; + // skip params setup if param list is empty + if (!$empty_params) { + $params_new[] = $params[$matches[3]] ?? + throw new \RuntimeException( + 'Cannot lookup ' . $matches[3] . ' in params list', + 210 + ); + } + } + // add the connectors back (1), and the data sets only if no replacement will be done + return $matches[1] . ( + empty($matches[3]) ? + $matches[2] : + $params_lookup[$matches[3]] ?? + throw new \RuntimeException( + 'Cannot lookup ' . $matches[3] . ' in params lookup list', + 211 + ) + ); + }, + $converted_placeholders['original']['query'] + ); + break; + case 'question_mark': + if (!$empty_params) { + // order and data stays the same + $params_new = $params ?? []; + } + // 0: full + // 1: pre part + // 2: keep part UNLESS '3' is set + // 3: replace part ? + $pos = 0; + $query_new = preg_replace_callback( + self::REGEX_REPLACE_QUESTION_MARK, + function ($matches) use (&$pos, &$params_lookup) { + // only count pos up for actual replacements we will do + if (!empty($matches[3])) { + $pos++; + $params_lookup[] = '$' . $pos; + } + // add the connectors back (1), and the data sets only if no replacement will be done + return $matches[1] . ( + empty($matches[3]) ? + $matches[2] : + '$' . $pos + ); + }, + $converted_placeholders['original']['query'] + ); + break; + case 'numbered': + // 0: full + // 1: pre part + // 2: keep part UNLESS '3' is set + // 3: replace part $numbered + $pos = 0; + $query_new = preg_replace_callback( + self::REGEX_REPLACE_NUMBERED, + function ($matches) use (&$pos, &$params_new, &$params_lookup, $params, $empty_params) { + // only count up if $match[3] is not yet in lookup table + if (!empty($matches[3]) && empty($params_lookup[$matches[3]])) { + $pos++; + $params_lookup[$matches[3]] = ':' . $pos . '_named'; + // skip params setup if param list is empty + if (!$empty_params) { + $params_new[] = $params[($pos - 1)] ?? + throw new \RuntimeException( + 'Cannot lookup ' . ($pos - 1) . ' in params list', + 220 + ); + } + } + // add the connectors back (1), and the data sets only if no replacement will be done + return $matches[1] . ( + empty($matches[3]) ? + $matches[2] : + $params_lookup[$matches[3]] ?? throw new \RuntimeException( 'Cannot lookup ' . $matches[3] . ' in params lookup list', - 211 + 221 ) - ); - }, - $query - ); - } elseif ($count_qmark && $convert_to == 'pg') { - $type = 'question_mark'; - $matches_return = $qmark_matches; - // order and data stays the same - $params_new = $params; - // only check for ? - $pattern_replace = '/' - . '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)' - . '(\d+|(?:\'.*?\')|(?:(?:\?\?)?\s*(\?{1})))' - . '/s'; - // 0: full - // 1: pre part - // 2: keep part UNLESS '3' is set - // 3: replace part ? - $pos = 0; - $query_new = preg_replace_callback( - $pattern_replace, - function ($matches) use (&$pos, &$params_lookup) { - // only count pos up for actual replacements we will do - if (!empty($matches[3])) { - $pos++; - $params_lookup[] = '$' . $pos; - } - // add the connectors back (1), and the data sets only if no replacement will be done - return $matches[1] . ( - empty($matches[3]) ? - $matches[2] : - '$' . $pos - ); - }, - $query - ); - // for each ?:DTN: -> replace with $1 ... $n, any remaining :DTN: remove - } elseif ($count_numbered && $convert_to == 'pdo') { - // convert numbered to named - $type = 'numbered'; - $matches_return = $numbered_matches; - // only check for $n - $pattern_replace = '/' - . '((?:\'.*?\')?\s*(?:\?\?|' . $query_split . ')\s*)' - . '(\d+|(?:\'.*?\')|(\$[1-9]{1}(?:[0-9]{1,})?))' - . '/s'; - // 0: full - // 1: pre part - // 2: keep part UNLESS '3' is set - // 3: replace part $numbered - $pos = 0; - $query_new = preg_replace_callback( - $pattern_replace, - function ($matches) use (&$pos, &$params_new, &$params_lookup, $params) { - // only count up if $match[3] is not yet in lookup table - if (!empty($matches[3]) && empty($params_lookup[$matches[3]])) { - $pos++; - $params_lookup[$matches[3]] = ':' . $pos . '_named'; - $params_new[] = $params[($pos - 1)] ?? - throw new \RuntimeException( - 'Cannot lookup ' . ($pos - 1) . ' in params list', - 220 - ); - } - // add the connectors back (1), and the data sets only if no replacement will be done - return $matches[1] . ( - empty($matches[3]) ? - $matches[2] : - $params_lookup[$matches[3]] ?? - throw new \RuntimeException( - 'Cannot lookup ' . $matches[3] . ' in params lookup list', - 221 - ) - ); - }, - $query - ); + ); + }, + $converted_placeholders['original']['query'] + ); + break; } - // return, old query is always set return [ - // original - 'original' => [ - 'query' => $query, - 'params' => $params, - ], - // type found, empty if nothing was done - 'type' => $type, - // int: found, not found; -1: problem (set from false) - 'found' => (int)$found, - 'matches' => $matches_return, - // old to new lookup check 'params_lookup' => $params_lookup, - // new 'query' => $query_new ?? '', 'params' => $params_new, ]; diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Language/Core/GetTextReader.php b/www/vendor/egrajp/corelibs-composer-all/src/Language/Core/GetTextReader.php index 0a5715a7..dd1ef96d 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Language/Core/GetTextReader.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Language/Core/GetTextReader.php @@ -190,7 +190,6 @@ class GetTextReader private function loadTables(): void { if ( - is_array($this->cache_translations) && is_array($this->table_originals) && is_array($this->table_translations) ) { @@ -318,10 +317,7 @@ class GetTextReader if ($this->enable_cache) { // Caching enabled, get translated string from cache - if ( - is_array($this->cache_translations) && - array_key_exists($string, $this->cache_translations) - ) { + if (array_key_exists($string, $this->cache_translations)) { return $this->cache_translations[$string]; } else { return $string; @@ -481,7 +477,7 @@ class GetTextReader $key = $single . chr(0) . $plural; if ($this->enable_cache) { - if (is_array($this->cache_translations) && !array_key_exists($key, $this->cache_translations)) { + if (!array_key_exists($key, $this->cache_translations)) { return ($number != 1) ? $plural : $single; } else { $result = $this->cache_translations[$key]; diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Output/Form/Generate.php b/www/vendor/egrajp/corelibs-composer-all/src/Output/Form/Generate.php index 62ca7370..68e7a1df 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Output/Form/Generate.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Output/Form/Generate.php @@ -474,7 +474,7 @@ class Generate $page_name_camel_case ); try { - /** @var TableArrays\Interface\TableArraysInterface|false $class */ + /** @var TableArrays\Interface\TableArraysInterface $class */ $class = new $class_string($this); } catch (\Throwable $t) { $this->log->critical('CLASS LOADING: Failed loading: ' . $class_string . ' => ' . $t->getMessage()); @@ -1757,14 +1757,9 @@ class Generate $this->dba->setTableArrayEntry($this->dba->getTableArray()[$key]['preset'], $key, 'value'); } } - if (is_array($this->reference_array)) { - if (!is_array($this->reference_array)) { - $this->reference_array = []; - } - reset($this->reference_array); - foreach ($this->reference_array as $key => $value) { - unset($this->reference_array[$key]['selected']); - } + reset($this->reference_array); + foreach ($this->reference_array as $key => $value) { + unset($this->reference_array[$key]['selected']); } $this->warning = 1; $this->msg = $this->l->__('Cleared for new Dataset!'); @@ -1787,20 +1782,15 @@ class Generate $this->dba->unsetTableArrayEntry($key, 'input_value'); } - if (is_array($this->reference_array)) { - // load each reference_table - if (!is_array($this->reference_array)) { - $this->reference_array = []; - } - reset($this->reference_array); - foreach ($this->reference_array as $key => $value) { - unset($this->reference_array[$key]['selected']); - $q = 'SELECT ' . $this->reference_array[$key]['other_table_pk'] - . ' FROM ' . $this->reference_array[$key]['table_name'] - . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; - while (is_array($res = $this->dba->dbReturn($q))) { - $this->reference_array[$key]['selected'][] = $res[$this->reference_array[$key]['other_table_pk']]; - } + // load each reference_table + reset($this->reference_array); + foreach ($this->reference_array as $key => $value) { + unset($this->reference_array[$key]['selected']); + $q = 'SELECT ' . $this->reference_array[$key]['other_table_pk'] + . ' FROM ' . $this->reference_array[$key]['table_name'] + . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; + while (is_array($res = $this->dba->dbReturn($q))) { + $this->reference_array[$key]['selected'][] = $res[$this->reference_array[$key]['other_table_pk']]; } } $this->warning = 1; @@ -1979,24 +1969,19 @@ class Generate // write the object $this->dba->dbWrite($addslashes, [], true); // write reference array (s) if necessary - if (is_array($this->reference_array)) { - if (!is_array($this->reference_array)) { - $this->reference_array = []; + reset($this->reference_array); + foreach ($this->reference_array as $reference_array) { + $q = 'DELETE FROM ' . $reference_array['table_name'] + . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; + $this->dba->dbExec($q); + $q = 'INSERT INTO ' . $reference_array['table_name'] + . ' (' . $reference_array['other_table_pk'] . ', ' . $this->int_pk_name . ') VALUES '; + for ($i = 0, $i_max = count($reference_array['selected']); $i < $i_max; $i++) { + $t_q = '(' . $reference_array['selected'][$i] . ', ' + . $this->dba->getTableArray()[$this->int_pk_name]['value'] . ')'; + $this->dba->dbExec($q . $t_q); } - reset($this->reference_array); - foreach ($this->reference_array as $reference_array) { - $q = 'DELETE FROM ' . $reference_array['table_name'] - . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; - $this->dba->dbExec($q); - $q = 'INSERT INTO ' . $reference_array['table_name'] - . ' (' . $reference_array['other_table_pk'] . ', ' . $this->int_pk_name . ') VALUES '; - for ($i = 0, $i_max = count($reference_array['selected']); $i < $i_max; $i++) { - $t_q = '(' . $reference_array['selected'][$i] . ', ' - . $this->dba->getTableArray()[$this->int_pk_name]['value'] . ')'; - $this->dba->dbExec($q . $t_q); - } - } // foreach reference arrays - } // if reference arrays + } // foreach reference arrays // write element list if (!empty($this->element_list)) { $type = []; @@ -2230,16 +2215,11 @@ class Generate public function formDeleteTableArray() { // remove any reference arrays - if (is_array($this->reference_array)) { - if (!is_array($this->reference_array)) { - $this->reference_array = []; - } - reset($this->reference_array); - foreach ($this->reference_array as $reference_array) { - $q = 'DELETE FROM ' . $reference_array['table_name'] - . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; - $this->dba->dbExec($q); - } + reset($this->reference_array); + foreach ($this->reference_array as $reference_array) { + $q = 'DELETE FROM ' . $reference_array['table_name'] + . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; + $this->dba->dbExec($q); } // remove any element list references if (!empty($this->element_list)) { diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Output/Image.php b/www/vendor/egrajp/corelibs-composer-all/src/Output/Image.php index 9fd82619..aa449602 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Output/Image.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Output/Image.php @@ -256,8 +256,8 @@ class Image } // check resize parameters if ($inc_width > $thumb_width || $inc_height > $thumb_height) { - $thumb_width_r = 0; - $thumb_height_r = 0; + $thumb_width_r = 1; + $thumb_height_r = 1; // we need to keep the aspect ration on longest side if ( ($inc_height > $inc_width && @@ -288,6 +288,12 @@ class Image !file_exists($thumbnail_write_path . $thumbnail) ) { // image, copy source image, offset in image, source x/y, new size, source image size + if ($thumb_width_r < 1) { + $thumb_width_r = 1; + } + if ($thumb_height_r < 1) { + $thumb_height_r = 1; + } $thumb = imagecreatetruecolor($thumb_width_r, $thumb_height_r); if ($thumb === false) { throw new \RuntimeException( @@ -380,9 +386,7 @@ class Image } } // add output path - if ($thumbnail !== false) { - $thumbnail = $thumbnail_web_path . $thumbnail; - } + $thumbnail = $thumbnail_web_path . $thumbnail; } elseif ($create_dummy === true) { // create dummy image in the thumbnail size // if one side is missing, use the other side to create a square @@ -399,10 +403,10 @@ class Image !file_exists($thumbnail_write_path . $thumbnail) ) { // if both are unset, set to 250 - if ($thumb_height == 0) { + if ($thumb_height < 1) { $thumb_height = 250; } - if ($thumb_width == 0) { + if ($thumb_width < 1) { $thumb_width = 250; } $thumb = imagecreatetruecolor($thumb_width, $thumb_height); diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Convert/CoreLibsConvertMathTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Convert/CoreLibsConvertMathTest.php index 6441ca79..5df06aa0 100644 --- a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Convert/CoreLibsConvertMathTest.php +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Convert/CoreLibsConvertMathTest.php @@ -319,6 +319,36 @@ final class CoreLibsConvertMathTest extends TestCase [6, 12, 18], ] ], + 'inblanaced [2x2,3] x [3x2]' => [ + 'a' => [ + [1, 2, 3], + [4, 5] + ], + 'b' => [ + [6, 7], + [8, 9], + [10, 11] + ], + 'result' => [ + [52, 58], + [64, 73], + ] + ], + 'inblanaced [2x3] x [3x1,2]' => [ + 'a' => [ + [1, 2, 3], + [4, 5, 7] + ], + 'b' => [ + [7, 8], + [9, 10], + [11] + ], + 'result' => [ + [58, 28], + [150, 82], + ] + ], ]; } diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/DB/CoreLibsDBIOTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/DB/CoreLibsDBIOTest.php index 93703db8..d6fa9408 100644 --- a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/DB/CoreLibsDBIOTest.php +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/DB/CoreLibsDBIOTest.php @@ -37,8 +37,9 @@ namespace tests; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\MockObject\MockObject; -use CoreLibs\Logging\Logger\Level; +use CoreLibs\Logging; use CoreLibs\DB\Options\Convert; +use CoreLibs\DB\Support\ConvertPlaceholder; /** * Test class for DB\IO + DB\SQL\PgSQL @@ -117,7 +118,7 @@ final class CoreLibsDBIOTest extends TestCase ); } // define basic connection set valid and one invalid - self::$log = new \CoreLibs\Logging\Logging([ + self::$log = new Logging\Logging([ // 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', 'log_file_id' => 'CoreLibs-DB-IO-Test', @@ -570,11 +571,11 @@ final class CoreLibsDBIOTest extends TestCase ); $db->dbClose(); // second conenction with log set NOT debug - $log = new \CoreLibs\Logging\Logging([ + $log = new Logging\Logging([ // 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', 'log_file_id' => 'CoreLibs-DB-IO-Test', - 'log_level' => \CoreLibs\Logging\Logger\Level::Notice, + 'log_level' => Logging\Logger\Level::Notice, ]); $db = new \CoreLibs\DB\IO( self::$db_config[$connection], @@ -3293,6 +3294,7 @@ final class CoreLibsDBIOTest extends TestCase 'query' => 'INSERT INTO table_with_primary_key (row_int, uid) ' . 'VALUES ($1, $2) RETURNING table_with_primary_key_id', 'returning_id' => true, + 'placeholder_converted' => [], ], ], // update @@ -3327,6 +3329,7 @@ final class CoreLibsDBIOTest extends TestCase 'query' => 'UPDATE table_with_primary_key SET row_int = $1, ' . 'row_varchar = $2 WHERE uid = $3', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // select @@ -3356,6 +3359,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 1, 'query' => 'SELECT row_int, uid FROM table_with_primary_key WHERE uid = $1', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // any query but with no parameters @@ -3388,6 +3392,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 0, 'query' => 'SELECT row_int, uid FROM table_with_primary_key', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // no statement name (25) @@ -3411,6 +3416,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 0, 'query' => '', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // no query (prepare 11) @@ -3435,6 +3441,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 0, 'query' => '', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // no db connection (prepare/execute 16) @@ -3464,6 +3471,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 0, 'query' => 'SELECT row_int, uid FROM table_with_primary_key', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // prepare with different statement name @@ -3489,6 +3497,7 @@ final class CoreLibsDBIOTest extends TestCase 'count' => 0, 'query' => 'SELECT row_int, uid FROM table_with_primary_key', 'returning_id' => false, + 'placeholder_converted' => [], ], ], // insert wrong data count compared to needed (execute 23) @@ -3514,10 +3523,12 @@ final class CoreLibsDBIOTest extends TestCase 'query' => 'INSERT INTO table_with_primary_key (row_int, uid) VALUES ' . '($1, $2) RETURNING table_with_primary_key_id', 'returning_id' => true, + 'placeholder_converted' => [], ], ], // execute does not return a result (22) // TODO execute does not return a result + // TODO prepared statement with placeholder params auto convert ]; } @@ -3662,7 +3673,7 @@ final class CoreLibsDBIOTest extends TestCase } // check dbGetPrepareCursorValue - foreach (['pk_name', 'count', 'query', 'returning_id'] as $key) { + foreach (['pk_name', 'count', 'query', 'returning_id', 'placeholder_converted'] as $key) { $this->assertEquals( $prepare_cursor[$key], $db->dbGetPrepareCursorValue($stm_name, $key), @@ -5031,8 +5042,151 @@ final class CoreLibsDBIOTest extends TestCase $db->dbClose(); } - // query placeholder convert + // MARK: QUERY PLACEHOLDERS + // test query placeholder detection for all possible sets + // ::dbPrepare + + /** + * placeholder sql + * + * @return array + */ + public function providerDbCountQueryParams(): array + { + return [ + 'one place holder' => [ + 'query' => 'SELECT row_varchar FROM table_with_primary_key WHERE row_varchar = $1', + 'count' => 1, + 'convert' => false, + ], + 'one place holder, json call' => [ + 'query' => "SELECT row_varchar FROM table_with_primary_key WHERE row_jsonb->>'data' = $1", + 'count' => 1, + 'convert' => false, + ], + 'one place holder, <> compare' => [ + 'query' => "SELECT row_varchar FROM table_with_primary_key WHERE row_varchar <> $1", + 'count' => 1, + 'convert' => false, + ], + 'one place holder, named' => [ + 'query' => "SELECT row_varchar FROM table_with_primary_key WHERE row_varchar <> :row_varchar", + 'count' => 1, + 'convert' => true, + ], + 'no replacement' => [ + 'query' => "SELECT row_varchar FROM table_with_primary_key WHERE row_varchar = '$1'", + 'count' => 0, + 'convert' => false, + ], + 'insert' => [ + 'query' => "INSERT INTO table_with_primary_key (row_varchar, row_jsonb, row_int) VALUES ($1, $2, $3)", + 'count' => 3, + 'convert' => false, + ], + 'update' => [ + 'query' => "UPDATE table_with_primary_key SET row_varchar = $1, row_jsonb = $2, row_int = $3 WHERE row_numeric = $4", + 'count' => 4, + 'convert' => false, + ], + 'multiple, multline' => [ + 'query' => << 3, + 'convert' => false, + ], + 'two digit numbers' => [ + 'query' => << 10, + 'convert' => false, + ], + 'things in brackets' => [ + 'query' => << 4, + 'convert' => false, + ], + 'number compare' => [ + 'query' => <<= $1 OR row_int <= $2 OR + row_int > $3 OR row_int < $4 + OR row_int = $5 OR row_int <> $6 + SQL, + 'count' => 6, + 'convert' => false, + ] + ]; + } + + /** + * Placeholder check and convert tests + * + * @covers ::dbPrepare + * @covers ::__dbCountQueryParams + * @onvers ::convertPlaceholderInQuery + * @dataProvider providerDbCountQueryParams + * @testdox Query replacement count test [$_dataName] + * + * @param string $query + * @param int $count + * @return void + */ + public function testDbCountQueryParams(string $query, int $count, bool $convert): void + { + $db = new \CoreLibs\DB\IO( + self::$db_config['valid'], + self::$log + ); + $id = sha1($query); + $db->dbSetConvertPlaceholder($convert); + $db->dbPrepare($id, $query); + // print "\n**\n"; + // print "PCount: " . $db->dbGetPrepareCursorValue($id, 'count') . "\n"; + // print "\n**\n"; + $this->assertEquals( + $count, + $db->dbGetPrepareCursorValue($id, 'count'), + 'DB count params' + ); + $placeholder = ConvertPlaceholder::convertPlaceholderInQuery($query, null, 'pg'); + // print "RES: " . print_r($placeholder, true) . "\n"; + $this->assertEquals( + $count, + $placeholder['needed'], + 'convert params' + ); + } + + /** + * query placeholder convert + * + * @return array + */ public function queryPlaceholderReplaceProvider(): array { // WHERE row_varchar = $1 @@ -5076,7 +5230,9 @@ final class CoreLibsDBIOTest extends TestCase WHERE row_varchar = $1 SQL, 'expected_params' => ['string a'], - ] + ], + // TODO: test with multiple entries + // TODO: test with same entry ($1, $1, :var, :var) ]; } @@ -5178,6 +5334,8 @@ final class CoreLibsDBIOTest extends TestCase // - data debug // dbDumpData + // MARK: ASYNC + // ASYNC at the end because it has 1s timeout // - asynchronous executions // dbExecAsync, dbCheckAsync diff --git a/www/vendor/gullevek/dotenv/composer.json b/www/vendor/gullevek/dotenv/composer.json index 7d8298c4..df2c9291 100644 --- a/www/vendor/gullevek/dotenv/composer.json +++ b/www/vendor/gullevek/dotenv/composer.json @@ -27,7 +27,9 @@ }, "require-dev": { "phpunit/phpunit": "^9", - "phpstan/phpstan": "^1.10", - "phan/phan": "^5.4" + "phan/phan": "^5.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0" } } diff --git a/www/vendor/gullevek/dotenv/src/DotEnv.php b/www/vendor/gullevek/dotenv/src/DotEnv.php index 01868f82..671bbec3 100644 --- a/www/vendor/gullevek/dotenv/src/DotEnv.php +++ b/www/vendor/gullevek/dotenv/src/DotEnv.php @@ -60,7 +60,7 @@ class DotEnv $block = false; $var = ''; $prefix_name = ''; - while ($line = fgets($fp)) { + while (($line = fgets($fp)) !== false) { // [] block must be a single line, or it will be ignored if (preg_match("/^\s*\[([\w_.\s]+)\]/", $line, $matches)) { $prefix_name = preg_replace("/\s+/", "_", $matches[1]) . "."; @@ -104,6 +104,9 @@ class DotEnv // just be sure it is init before we fill if (!isset($_ENV[$var])) { $_ENV[$var] = ''; + } elseif (!is_string($_ENV[$var])) { + // if this is not string, skip + continue; } // strip line of slashes $_ENV[$var] .= stripslashes($line);