From 3fb7169531eff17dfbc7e94c6a5652d0b0148443 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Thu, 16 Jan 2025 10:25:19 +0900 Subject: [PATCH] CoreLibs update --- www/admin/class_test.db.php | 20 +-- www/admin/class_test.db.query-placeholder.php | 22 +++- www/admin/class_test.db.types.php | 45 ++++++- www/admin/class_test.output.form.php | 8 +- www/admin/class_test.password.php | 16 +++ www/admin/class_test.smarty.php | 4 + www/composer.lock | 13 +- www/vendor/composer/InstalledVersions.php | 11 +- www/vendor/composer/installed.json | 2 +- www/vendor/composer/installed.php | 2 +- .../publish/last.published | 2 +- .../src/Admin/EditBase.php | 7 +- .../src/Create/Session.php | 17 ++- .../src/DB/Support/ConvertPlaceholder.php | 4 +- .../src/Security/SymmetricEncryption.php | 5 +- .../src/Template/SmartyExtend.php | 123 +++++++++++++++--- .../test/phpunit/DB/CoreLibsDBIOTest.php | 21 +++ .../Security/CoreLibsSecurityPasswordTest.php | 14 ++ 18 files changed, 278 insertions(+), 58 deletions(-) diff --git a/www/admin/class_test.db.php b/www/admin/class_test.db.php index 4f1bfb82..eb9ba2e6 100644 --- a/www/admin/class_test.db.php +++ b/www/admin/class_test.db.php @@ -273,8 +273,8 @@ $query_insert = <<PREPARE QUERIES
"; // READ PREPARE $q_prep = <<dbPrepare('sel_test_foo', $q_prep) === false) { // sel test with ANY () type $q_prep = "SELECT test_foo_id, test, some_bool, string_a, number_a, " - . "number_a_numeric, some_time " + . "numeric_a, some_time " . "FROM test_foo " . "WHERE test = ANY($1) " . "ORDER BY test_foo_id DESC LIMIT 5"; @@ -618,7 +618,7 @@ $test_bar = $db->dbEscapeLiteral('SOMETHING DIFFERENT'); $q = <<"; $q = <<"; print "DB RETURN PARAMS LIKE
"; $q = <<"; print "DB RETURN PARAMS ANY
"; $q = <<dbReturnParams($query, [$query_value]))) { echo "
"; +echo "CASE part
"; +$query = << 1 THEN $1 + ELSE 1::INT + END)::INT +WHERE + string_a = $2 +SQL; +echo "QUERY:
" . $query . "
"; +$res = $db->dbExecParams($query, [1, 'foobar']); +print "ERROR: " . $db->dbGetLastError(true) . "
"; + +echo "
"; + // test connectors: = , <> () for query detection // convert placeholder tests @@ -237,7 +257,7 @@ SQL, SQL, 'params' => [1, 2, 3, 4, 5, 6], 'direction' => 'pg' - ] + ], ]; $db->dbSetConvertPlaceholder(true); diff --git a/www/admin/class_test.db.types.php b/www/admin/class_test.db.types.php index d3c74038..b302c330 100644 --- a/www/admin/class_test.db.types.php +++ b/www/admin/class_test.db.types.php @@ -57,6 +57,43 @@ if (($dbh = $db->dbGetDbh()) instanceof \PgSql\Connection) { print "TRUNCATE test_foo
"; $db->dbExec("TRUNCATE test_foo"); +/* +BELOW IS THE FULL TABLE WITH ALL PostgreSQL Types +=> \d test_foo + Table "public.test_foo" +Column | Type | Nullable | Default +------------------+-----------------------------+----------+----------------------------------------------- +test | character varying | | +some_bool | boolean | | +string_a | character varying | | +number_a | integer | | +numeric_a | numeric | | +some_internval | interval | | +test_foo_id | integer | not null | generated always as identity +json_string | jsonb | | +some_timestamp | timestamp without time zone | | +some_binary | bytea | | +null_var | character varying | | +smallint_a | smallint | | +number_real | real | | +number_double | double precision | | +number_serial | integer | not null | nextval('test_foo_number_serial_seq'::regclass) +array_char_1 | character varying[] | | +array_char_2 | character varying[] | | +array_int_1 | integer[] | | +array_int_2 | integer[] | | +composite_item | inventory_item | | +array_composite | inventory_item[] | | +numeric_3 | numeric(3,0) | | +identity_always | bigint | not null | generated always as identity +identitiy_default | bigint | not null | generated by default as identity +uuid_var | uuid | | gen_random_uuid() +some_date | date | | +some_time | time without time zone | | +bigint_a | bigint | | +default_uuid | uuid | | gen_random_uuid() +*/ + /* $q = <<"; $query_select = << [ + 'foo', + 'bar' ], // laod query - 'load_query' => '', + 'load_query' => 'SELECT uuid_nr, foo, bar FROM test', // database table to load from - 'table_name' => '', + 'table_name' => 'test', // for load dro pdown, format output 'show_fields' => [ [ - 'name' => 'name' + 'name' => 'foo' ], [ 'name' => 'enabled', diff --git a/www/admin/class_test.password.php b/www/admin/class_test.password.php index b1aa9de1..7176fc80 100644 --- a/www/admin/class_test.password.php +++ b/www/admin/class_test.password.php @@ -37,6 +37,8 @@ print ""; print ''; print '

' . $PAGE_NAME . '

'; +print "PHP Version: " . PHP_VERSION . "
"; + $password = 'something1234'; $enc_password = $_password->passwordSet($password); print "PASSWORD: $password: " . $enc_password . "
"; @@ -51,6 +53,20 @@ print "PASSWORD REHASH: " . (string)$password_class::passwordRehashCheck($enc_pa // direct static print "S::PASSWORD VERFIY: " . (string)PwdChk::passwordVerify($password, $enc_password) . "
"; +if (PHP_VERSION_ID < 80400) { + $rehash_test = '$2y$10$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W'; + $rehash_test_throw = '$2y$12$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W'; +} else { + $rehash_test = '$2y$12$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W'; + $rehash_test_throw = '$2y$10$EgWJ2WE73DWi.hIyFRCdpejLXTvHbmTK3LEOclO1tAvXAXUNuUS4W'; +} +if (PwdChk::passwordRehashCheck($rehash_test)) { + print "Bad password [BAD]
"; +} +if (PwdChk::passwordRehashCheck($rehash_test_throw)) { + print "Bad password [OK]
"; +} + print ""; // __END__ diff --git a/www/admin/class_test.smarty.php b/www/admin/class_test.smarty.php index 31635910..49e95ae9 100644 --- a/www/admin/class_test.smarty.php +++ b/www/admin/class_test.smarty.php @@ -4,6 +4,8 @@ * @phan-file-suppress PhanTypeSuspiciousStringExpression */ +// FIXME: Smarty Class must be updated for PHP 8.4 + declare(strict_types=1); error_reporting(E_ALL | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR); @@ -33,6 +35,7 @@ $l10n = new \CoreLibs\Language\L10n( ); $smarty = new CoreLibs\Template\SmartyExtend( $l10n, + $log, CACHE_ID, COMPILE_ID, ); @@ -45,6 +48,7 @@ $adm = new CoreLibs\Admin\Backend( ); $adm->DATA['adm_set'] = 'SET from admin class'; + $PAGE_NAME = 'TEST CLASS: SMARTY'; print ""; print "" . $PAGE_NAME . ""; diff --git a/www/composer.lock b/www/composer.lock index 4d00c05f..2d526e1b 100644 --- a/www/composer.lock +++ b/www/composer.lock @@ -12,7 +12,7 @@ "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "4ee141f8df16ecf8b4d32fb8763959e88ccc6914" + "reference": "a092217201ffac165dfcf72077c1fec14c759885" }, "require": { "php": ">=8.2", @@ -63,6 +63,13 @@ "url": "https://git.egplusww.jp/api/packages/Composer/composer/files/egrajp%2Fsmarty-extended/4.5.2/egrajp-smarty-extended.4.5.2.zip", "shasum": "a2c67a5047aad349a2cfa54240a44da449df9c4c" }, + "require": { + "ext-mbstring": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "egrajp/corelibs-composer-all": "^9" + }, "type": "library", "autoload": { "classmap": [ @@ -200,7 +207,7 @@ }, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [], + "platform": {}, + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/www/vendor/composer/InstalledVersions.php b/www/vendor/composer/InstalledVersions.php index 51e734a7..07b32ed6 100644 --- a/www/vendor/composer/InstalledVersions.php +++ b/www/vendor/composer/InstalledVersions.php @@ -322,6 +322,7 @@ class InstalledVersions } $installed = array(); + $copiedLocalDir = false; if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { @@ -330,9 +331,11 @@ class InstalledVersions } elseif (is_file($vendorDir.'/composer/installed.php')) { /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ $required = require $vendorDir.'/composer/installed.php'; - $installed[] = self::$installedByVendor[$vendorDir] = $required; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $required; + $copiedLocalDir = true; } } } @@ -350,7 +353,7 @@ class InstalledVersions } } - if (self::$installed !== array()) { + if (self::$installed !== array() && !$copiedLocalDir) { $installed[] = self::$installed; } diff --git a/www/vendor/composer/installed.json b/www/vendor/composer/installed.json index 997be827..20aba712 100644 --- a/www/vendor/composer/installed.json +++ b/www/vendor/composer/installed.json @@ -7,7 +7,7 @@ "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "4ee141f8df16ecf8b4d32fb8763959e88ccc6914" + "reference": "a092217201ffac165dfcf72077c1fec14c759885" }, "require": { "php": ">=8.2", diff --git a/www/vendor/composer/installed.php b/www/vendor/composer/installed.php index 221a2bfc..044ff02f 100644 --- a/www/vendor/composer/installed.php +++ b/www/vendor/composer/installed.php @@ -13,7 +13,7 @@ 'egrajp/corelibs-composer-all' => array( 'pretty_version' => 'dev-development', 'version' => 'dev-development', - 'reference' => '4ee141f8df16ecf8b4d32fb8763959e88ccc6914', + 'reference' => 'a092217201ffac165dfcf72077c1fec14c759885', 'type' => 'library', 'install_path' => __DIR__ . '/../egrajp/corelibs-composer-all', 'aliases' => array(), diff --git a/www/vendor/egrajp/corelibs-composer-all/publish/last.published b/www/vendor/egrajp/corelibs-composer-all/publish/last.published index 5c7cda31..2c53cf23 100644 --- a/www/vendor/egrajp/corelibs-composer-all/publish/last.published +++ b/www/vendor/egrajp/corelibs-composer-all/publish/last.published @@ -1 +1 @@ -9.24.1 +9.25.3 diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Admin/EditBase.php b/www/vendor/egrajp/corelibs-composer-all/src/Admin/EditBase.php index 27d4a162..20312b52 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Admin/EditBase.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Admin/EditBase.php @@ -14,9 +14,6 @@ declare(strict_types=1); namespace CoreLibs\Admin; -use Exception; -use SmartyException; - class EditBase { /** @var array */ @@ -63,6 +60,7 @@ class EditBase // smarty template engine (extended Translation version) $this->smarty = new \CoreLibs\Template\SmartyExtend( $l10n, + $log, $options['cache_id'] ?? '', $options['compile_id'] ?? '', ); @@ -538,8 +536,7 @@ class EditBase * builds the smarty content and runs smarty display output * * @return void - * @throws Exception - * @throws SmartyException + * @throws \Smarty\Exception */ public function editBaseRun( ?string $template_dir = null, diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Create/Session.php b/www/vendor/egrajp/corelibs-composer-all/src/Create/Session.php index b3f9f772..4440b47e 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Create/Session.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Create/Session.php @@ -363,11 +363,12 @@ class Session * set the auto write close flag * * @param bool $flag - * @return void + * @return Session */ - public function setAutoWriteClose(bool $flag): void + public function setAutoWriteClose(bool $flag): Session { $this->auto_write_close = $flag; + return $this; } /** @@ -513,14 +514,15 @@ class Session * * @param string $name array name in _SESSION * @param mixed $value value to set (can be anything) - * @return void + * @return Session */ - public function set(string $name, mixed $value): void + public function set(string $name, mixed $value): Session { $this->checkValidSessionEntryKey($name); $this->restartSession(); $_SESSION[$name] = $value; $this->closeSessionCall(); + return $this; } /** @@ -577,16 +579,17 @@ class Session * unset one _SESSION entry 'name' if exists * * @param string $name _SESSION key name to remove - * @return void + * @return Session */ - public function unset(string $name): void + public function unset(string $name): Session { if (!isset($_SESSION[$name])) { - return; + return $this; } $this->restartSession(); unset($_SESSION[$name]); $this->closeSessionCall(); + return $this; } /** 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 dff03788..484b7828 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 @@ -26,7 +26,9 @@ class ConvertPlaceholder . '&&|' // array overlap . '\-\|\-|' // range overlap for array . '[^-]-{1}|' // single -, used in JSON too - . '->|->>|#>|#>>|@>|<@|@@|@\?|\?{1}|\?\||\?&|#-'; //JSON searches, Array searchs, etc + . '->|->>|#>|#>>|@>|<@|@@|@\?|\?{1}|\?\||\?&|#-|' // JSON searches, Array searchs, etc + . 'THEN|ELSE' // command parts (CASE) + ; /** @var string the main regex including the pattern query split */ private const PATTERN_ELEMENT = '(?:\'.*?\')?\s*(?:' . self::PATTERN_QUERY_SPLIT . ')\s*'; /** @var string comment regex diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Security/SymmetricEncryption.php b/www/vendor/egrajp/corelibs-composer-all/src/Security/SymmetricEncryption.php index 91d8c2cb..08826212 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Security/SymmetricEncryption.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Security/SymmetricEncryption.php @@ -209,13 +209,13 @@ class SymmetricEncryption * set a new key for encryption * * @param string $key - * @return void + * @return SymmetricEncryption * @throws \UnexpectedValueException key cannot be empty */ public function setKey( #[\SensitiveParameter] string $key - ) { + ): SymmetricEncryption { if (empty($key)) { throw new \UnexpectedValueException('Key cannot be empty'); } @@ -224,6 +224,7 @@ class SymmetricEncryption // set key $this->key = $key; sodium_memzero($key); + return $this; } /** diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/SmartyExtend.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/SmartyExtend.php index e9b906d6..10eaa981 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Template/SmartyExtend.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/SmartyExtend.php @@ -19,12 +19,13 @@ declare(strict_types=1); namespace CoreLibs\Template; -// leading slash if this is in lib\Smarty -class SmartyExtend extends \Smarty +class SmartyExtend extends \Smarty\Smarty { // internal translation engine - /** @var \CoreLibs\Language\L10n */ + /** @var \CoreLibs\Language\L10n language class */ public \CoreLibs\Language\L10n $l10n; + /** @var \CoreLibs\Logging\Logging $log logging class */ + public \CoreLibs\Logging\Logging $log; // lang & encoding /** @var string */ @@ -157,14 +158,18 @@ class SmartyExtend extends \Smarty * calls L10 for pass on internaly in smarty * also registers the getvar caller plugin * - * @param \CoreLibs\Language\L10n $l10n l10n language class - * @param string|null $cache_id - * @param string|null $compile_id + * @param \CoreLibs\Language\L10n $l10n l10n language class + * @param \CoreLibs\Logging\Logging $log Logger class + * @param string|null $cache_id [default=null] + * @param string|null $compile_id [default=null] + * @param array $options [default=[]] */ public function __construct( \CoreLibs\Language\L10n $l10n, + \CoreLibs\Logging\Logging $log, ?string $cache_id = null, - ?string $compile_id = null + ?string $compile_id = null, + array $options = [] ) { // trigger deprecation if ( @@ -177,14 +182,33 @@ class SmartyExtend extends \Smarty E_USER_DEPRECATED ); } - // set variables (to be deprecated) - $cache_id = $cache_id ?? - (defined('CACHE_ID') ? CACHE_ID : ''); - $compile_id = $compile_id ?? - (defined('COMPILE_ID') ? COMPILE_ID : ''); + // set variables from global constants (deprecated) + if ($cache_id === null && defined('CACHE_ID')) { + trigger_error( + 'SmartyExtended: No cache_id set and CACHE_ID constant set, this is deprecated', + E_USER_DEPRECATED + ); + $cache_id = CACHE_ID; + } + if ($compile_id === null && defined('COMPILE_ID')) { + trigger_error( + 'SmartyExtended: No compile_id set and COMPILE_ID constant set, this is deprecated', + E_USER_DEPRECATED + ); + $compile_id = COMPILE_ID; + } + if (empty($cache_id)) { + throw new \BadMethodCallException('cache_id parameter is not set'); + } + if (empty($compile_id)) { + throw new \BadMethodCallException('compile_id parameter is not set'); + } + // call basic smarty - // or Smarty::__construct(); parent::__construct(); + + $this->log = $log; + // init lang $this->l10n = $l10n; // parse and read, legacy stuff @@ -194,7 +218,6 @@ class SmartyExtend extends \Smarty $this->lang_short = $locale['lang_short']; $this->domain = $locale['domain']; $this->lang_dir = $locale['path']; - // opt load functions so we can use legacy init for smarty run perhaps \CoreLibs\Language\L10n::loadFunctions(); _setlocale(LC_MESSAGES, $locale['locale']); @@ -203,7 +226,6 @@ class SmartyExtend extends \Smarty _bind_textdomain_codeset($this->domain, $this->encoding); // register smarty variable - // $this->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'getvar', [&$this, 'getTemplateVars']); $this->registerPlugin(self::PLUGIN_MODIFIER, 'getvar', [&$this, 'getTemplateVars']); $this->page_name = \CoreLibs\Get\System::getPageName(); @@ -211,6 +233,77 @@ class SmartyExtend extends \Smarty // set internal settings $this->CACHE_ID = $cache_id; $this->COMPILE_ID = $compile_id; + // set options + $this->setOptions($options); + } + + /** + * set options + * + * @param array $options + * @return void + */ + private function setOptions(array $options): void + { + // set escape html if option is set + if (!empty($options['escape_html'])) { + $this->setEscapeHtml(true); + } + // load plugins + // plugin array: + // 'file': string, path to plugin content to load + // 'type': a valid smarty type see Smarty PLUGIN_ constants for correct names + // 'tag': the smarty tag + // 'callback': the function to call in 'file' + if (!empty($options['plugins'])) { + foreach ($options['plugins'] as $plugin) { + // file is readable + if ( + empty($plugin['file']) || + !is_file($plugin['file']) || + !is_readable($plugin['file']) + ) { + $this->log->warning('SmartyExtended plugin load failed, file not accessable', [ + 'plugin' => $plugin, + ]); + continue; + } + // tag is alphanumeric + if (!preg_match("/^\w+$/", $plugin['tag'] ?? '')) { + $this->log->warning('SmartyExtended plugin load failed, invalid tag', [ + 'plugin' => $plugin, + ]); + continue; + } + // callback is alphanumeric + if (!preg_match("/^\w+$/", $plugin['callback'] ?? '')) { + $this->log->warning('SmartyExtended plugin load failed, invalid callback', [ + 'plugin' => $plugin, + ]); + continue; + } + try { + /** @phan-suppress-next-line PhanNoopNew */ + new \ReflectionClassConstant($this, $plugin['type']); + } catch (\ReflectionException $e) { + $this->log->error('SmartyExtended plugin load failed, type is not valid', [ + 'message' => $e->getMessage(), + 'plugin' => $plugin, + ]); + continue; + } + try { + require $plugin['file']; + $this->registerPlugin($plugin['type'], $plugin['tag'], $plugin['callback']); + } catch (\Smarty\Exception $e) { + $this->log->error('SmartyExtended plugin load failed with exception', [ + 'message' => $e->getMessage(), + 'plugin' => $plugin, + ]); + continue; + } + } + } } /** 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 14767292..ac6314d6 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 @@ -5196,6 +5196,27 @@ final class CoreLibsDBIOTest extends TestCase SQL, 'count' => 1, 'convert' => false, + ], + 'update with case' => [ + 'query' => << 3, + 'convert' => false, + ], + 'select with case' => [ + 'query' => << 2, + 'convert' => false, ] ]; } diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecurityPasswordTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecurityPasswordTest.php index 80adec64..7904997a 100644 --- a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecurityPasswordTest.php +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecurityPasswordTest.php @@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase; */ final class CoreLibsSecurityPasswordTest extends TestCase { + /** + * Undocumented function + * + * @return array + */ public function passwordProvider(): array { return [ @@ -21,6 +26,11 @@ final class CoreLibsSecurityPasswordTest extends TestCase ]; } + /** + * Note: we need different hash types for PHP versions + * + * @return array + */ public function passwordRehashProvider(): array { return [ @@ -63,6 +73,10 @@ final class CoreLibsSecurityPasswordTest extends TestCase */ public function testPasswordRehashCheck(string $input, bool $expected): void { + // in PHP 8.4 the length is $12 + if (PHP_VERSION_ID > 80400) { + $input = str_replace('$2y$10$', '$2y$12$', $input); + } $this->assertEquals( $expected, \CoreLibs\Security\Password::passwordRehashCheck($input)