From 6cbbf601b047f1c60de3f9f7d4003b2aa46f3fa3 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Fri, 27 Dec 2024 08:14:06 +0100 Subject: [PATCH 1/5] fix: handling binary data for prepared statement (#9337) * fix prepare statement sqlite * fix prepare statement postgre * fix prepare statement sqlsrv * fix prepare statement oci8 * tests * abstract isBinary() method * fix prepare statement mysqli * fix prepare statement oci8 * sqlsrv blob support * fix tests * add changelog * fix rector * make sqlsrv happy * make oci8 happy - hopefully * add a note about options for prepared statement * ignore PreparedQueryTest.php file * apply code suggestion for oci8 --- .php-cs-fixer.tests.php | 1 + system/Database/BasePreparedQuery.php | 8 +++++ system/Database/MySQLi/PreparedQuery.php | 15 ++++++-- system/Database/OCI8/PreparedQuery.php | 15 +++++++- system/Database/Postgre/Forge.php | 4 +++ system/Database/Postgre/PreparedQuery.php | 6 ++++ system/Database/SQLSRV/Connection.php | 6 +++- system/Database/SQLSRV/Forge.php | 5 +++ system/Database/SQLSRV/PreparedQuery.php | 12 +++++-- system/Database/SQLite3/PreparedQuery.php | 2 ++ .../20160428212500_Create_test_tables.php | 3 +- .../Live/AbstractGetFieldDataTestCase.php | 10 +++--- .../Live/Postgre/GetFieldDataTestCase.php | 7 ++++ .../Database/Live/PreparedQueryTest.php | 35 +++++++++++++++++++ .../Live/SQLSRV/GetFieldDataTestCase.php | 7 ++++ user_guide_src/source/changelogs/v4.5.6.rst | 3 +- user_guide_src/source/database/queries.rst | 2 ++ 17 files changed, 124 insertions(+), 17 deletions(-) diff --git a/.php-cs-fixer.tests.php b/.php-cs-fixer.tests.php index 28a7124909e5..bf37256da58a 100644 --- a/.php-cs-fixer.tests.php +++ b/.php-cs-fixer.tests.php @@ -26,6 +26,7 @@ '_support/View/Cells/multiplier.php', '_support/View/Cells/colors.php', '_support/View/Cells/addition.php', + 'system/Database/Live/PreparedQueryTest.php', ]) ->notName('#Foobar.php$#'); diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index 8c4f252cfb7e..6ba2f6eb5a43 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -259,4 +259,12 @@ public function getErrorMessage(): string { return $this->errorString; } + + /** + * Whether the input contain binary data. + */ + protected function isBinary(string $input): bool + { + return mb_detect_encoding($input, 'UTF-8', true) === false; + } } diff --git a/system/Database/MySQLi/PreparedQuery.php b/system/Database/MySQLi/PreparedQuery.php index e9a6c6d10e30..34eedc25ff15 100644 --- a/system/Database/MySQLi/PreparedQuery.php +++ b/system/Database/MySQLi/PreparedQuery.php @@ -66,15 +66,19 @@ public function _execute(array $data): bool throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.'); } - // First off -bind the parameters - $bindTypes = ''; + // First off - bind the parameters + $bindTypes = ''; + $binaryData = []; // Determine the type string - foreach ($data as $item) { + foreach ($data as $key => $item) { if (is_int($item)) { $bindTypes .= 'i'; } elseif (is_numeric($item)) { $bindTypes .= 'd'; + } elseif (is_string($item) && $this->isBinary($item)) { + $bindTypes .= 'b'; + $binaryData[$key] = $item; } else { $bindTypes .= 's'; } @@ -83,6 +87,11 @@ public function _execute(array $data): bool // Bind it $this->statement->bind_param($bindTypes, ...$data); + // Stream binary data + foreach ($binaryData as $key => $value) { + $this->statement->send_long_data($key, $value); + } + try { return $this->statement->execute(); } catch (mysqli_sql_exception $e) { diff --git a/system/Database/OCI8/PreparedQuery.php b/system/Database/OCI8/PreparedQuery.php index feffc3be50b5..e1577642c3a9 100644 --- a/system/Database/OCI8/PreparedQuery.php +++ b/system/Database/OCI8/PreparedQuery.php @@ -16,6 +16,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; use CodeIgniter\Database\Exceptions\DatabaseException; +use OCILob; /** * Prepared query for OCI8 @@ -73,12 +74,24 @@ public function _execute(array $data): bool throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.'); } + $binaryData = null; + foreach (array_keys($data) as $key) { - oci_bind_by_name($this->statement, ':' . $key, $data[$key]); + if (is_string($data[$key]) && $this->isBinary($data[$key])) { + $binaryData = oci_new_descriptor($this->db->connID, OCI_D_LOB); + $binaryData->writeTemporary($data[$key], OCI_TEMP_BLOB); + oci_bind_by_name($this->statement, ':' . $key, $binaryData, -1, OCI_B_BLOB); + } else { + oci_bind_by_name($this->statement, ':' . $key, $data[$key]); + } } $result = oci_execute($this->statement, $this->db->commitMode); + if ($binaryData instanceof OCILob) { + $binaryData->free(); + } + if ($result && $this->lastInsertTableName !== '') { $this->db->lastInsertedTableName = $this->lastInsertTableName; } diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index b516172737ae..704f3e576047 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -173,6 +173,10 @@ protected function _attributeType(array &$attributes) $attributes['TYPE'] = 'TIMESTAMP'; break; + case 'BLOB': + $attributes['TYPE'] = 'BYTEA'; + break; + default: break; } diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php index 33a6c8044c7d..c55d5d8c5402 100644 --- a/system/Database/Postgre/PreparedQuery.php +++ b/system/Database/Postgre/PreparedQuery.php @@ -87,6 +87,12 @@ public function _execute(array $data): bool throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.'); } + foreach ($data as &$item) { + if (is_string($item) && $this->isBinary($item)) { + $item = pg_escape_bytea($this->db->connID, $item); + } + } + $this->result = pg_execute($this->db->connID, $this->name, $data); return (bool) $this->result; diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index 7d60ad1cabd1..8ded4cd02098 100644 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -368,7 +368,11 @@ protected function _fieldData(string $table): array $retVal[$i]->max_length = $query[$i]->CHARACTER_MAXIMUM_LENGTH > 0 ? $query[$i]->CHARACTER_MAXIMUM_LENGTH - : $query[$i]->NUMERIC_PRECISION; + : ( + $query[$i]->CHARACTER_MAXIMUM_LENGTH === -1 + ? 'max' + : $query[$i]->NUMERIC_PRECISION + ); $retVal[$i]->nullable = $query[$i]->IS_NULLABLE !== 'NO'; $retVal[$i]->default = $query[$i]->COLUMN_DEFAULT; diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index d121560c9d47..df3d55c779c4 100644 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -397,6 +397,11 @@ protected function _attributeType(array &$attributes) $attributes['TYPE'] = 'BIT'; break; + case 'BLOB': + $attributes['TYPE'] = 'VARBINARY'; + $attributes['CONSTRAINT'] ??= 'MAX'; + break; + default: break; } diff --git a/system/Database/SQLSRV/PreparedQuery.php b/system/Database/SQLSRV/PreparedQuery.php index f3a4a14c2bc6..425555927c60 100644 --- a/system/Database/SQLSRV/PreparedQuery.php +++ b/system/Database/SQLSRV/PreparedQuery.php @@ -59,7 +59,7 @@ public function _prepare(string $sql, array $options = []): PreparedQuery // Prepare parameters for the query $queryString = $this->getQueryString(); - $parameters = $this->parameterize($queryString); + $parameters = $this->parameterize($queryString, $options); // Prepare the query $this->statement = sqlsrv_prepare($this->db->connID, $sql, $parameters); @@ -120,8 +120,10 @@ protected function _close(): bool /** * Handle parameters. + * + * @param array $options */ - protected function parameterize(string $queryString): array + protected function parameterize(string $queryString, array $options): array { $numberOfVariables = substr_count($queryString, '?'); @@ -129,7 +131,11 @@ protected function parameterize(string $queryString): array for ($c = 0; $c < $numberOfVariables; $c++) { $this->parameters[$c] = null; - $params[] = &$this->parameters[$c]; + if (isset($options[$c])) { + $params[] = [&$this->parameters[$c], SQLSRV_PARAM_IN, $options[$c]]; + } else { + $params[] = &$this->parameters[$c]; + } } return $params; diff --git a/system/Database/SQLite3/PreparedQuery.php b/system/Database/SQLite3/PreparedQuery.php index 21dc4c2fdeff..0e15b5d61f3b 100644 --- a/system/Database/SQLite3/PreparedQuery.php +++ b/system/Database/SQLite3/PreparedQuery.php @@ -75,6 +75,8 @@ public function _execute(array $data): bool $bindType = SQLITE3_INTEGER; } elseif (is_float($item)) { $bindType = SQLITE3_FLOAT; + } elseif (is_string($item) && $this->isBinary($item)) { + $bindType = SQLITE3_BLOB; } else { $bindType = SQLITE3_TEXT; } diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index cf567ace96cf..434644bef280 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -99,8 +99,7 @@ public function up(): void unset( $dataTypeFields['type_set'], $dataTypeFields['type_mediumtext'], - $dataTypeFields['type_double'], - $dataTypeFields['type_blob'] + $dataTypeFields['type_double'] ); } diff --git a/tests/system/Database/Live/AbstractGetFieldDataTestCase.php b/tests/system/Database/Live/AbstractGetFieldDataTestCase.php index 60413acc784f..011564992922 100644 --- a/tests/system/Database/Live/AbstractGetFieldDataTestCase.php +++ b/tests/system/Database/Live/AbstractGetFieldDataTestCase.php @@ -104,8 +104,8 @@ protected function createTableForType(): void $this->forge->dropTable($this->table, true); // missing types: - // TINYINT,MEDIUMINT,BIT,YEAR,BINARY,VARBINARY,TINYTEXT,LONGTEXT, - // JSON,Spatial data types + // TINYINT,MEDIUMINT,BIT,YEAR,BINARY,VARBINARY (BLOB more or less handles these two), + // TINYTEXT,LONGTEXT,JSON,Spatial data types // `id` must be INTEGER else SQLite3 error on not null for autoincrement field. $fields = [ 'id' => ['type' => 'INTEGER', 'constraint' => 20, 'auto_increment' => true], @@ -138,8 +138,7 @@ protected function createTableForType(): void $fields['type_enum'], $fields['type_set'], $fields['type_mediumtext'], - $fields['type_double'], - $fields['type_blob'] + $fields['type_double'] ); } @@ -147,8 +146,7 @@ protected function createTableForType(): void unset( $fields['type_set'], $fields['type_mediumtext'], - $fields['type_double'], - $fields['type_blob'] + $fields['type_double'] ); } diff --git a/tests/system/Database/Live/Postgre/GetFieldDataTestCase.php b/tests/system/Database/Live/Postgre/GetFieldDataTestCase.php index 42e823397926..0adfc036c4c3 100644 --- a/tests/system/Database/Live/Postgre/GetFieldDataTestCase.php +++ b/tests/system/Database/Live/Postgre/GetFieldDataTestCase.php @@ -212,6 +212,13 @@ public function testGetFieldDataType(): void 'default' => null, ], 15 => (object) [ + 'name' => 'type_blob', + 'type' => 'bytea', + 'max_length' => null, + 'nullable' => true, + 'default' => null, + ], + 16 => (object) [ 'name' => 'type_boolean', 'type' => 'boolean', 'max_length' => null, diff --git a/tests/system/Database/Live/PreparedQueryTest.php b/tests/system/Database/Live/PreparedQueryTest.php index fd3b6cedb403..80e0addbca82 100644 --- a/tests/system/Database/Live/PreparedQueryTest.php +++ b/tests/system/Database/Live/PreparedQueryTest.php @@ -269,4 +269,39 @@ public function testDeallocatePreparedQueryThenTryToClose(): void $this->query->close(); } + + public function testInsertBinaryData(): void + { + $params = []; + if ($this->db->DBDriver === 'SQLSRV') { + $params = [0 => SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)]; + } + + $this->query = $this->db->prepare(static fn ($db) => $db->table('type_test')->insert([ + 'type_blob' => 'binary', + ]), $params); + + $fileContent = file_get_contents(TESTPATH . '_support/Images/EXIFsamples/landscape_0.jpg'); + $this->assertTrue($this->query->execute($fileContent)); + + $id = $this->db->DBDriver === 'SQLSRV' + // It seems like INSERT for a prepared statement is run in the + // separate execution context even though it's part of the same session + ? (int) ($this->db->query('SELECT @@IDENTITY AS insert_id')->getRow()->insert_id ?? 0) + : $this->db->insertID(); + $builder = $this->db->table('type_test'); + + if ($this->db->DBDriver === 'Postgre') { + $file = $builder->select("ENCODE(type_blob, 'base64') AS type_blob")->where('id', $id)->get()->getRow(); + $file = base64_decode($file->type_blob, true); + } elseif ($this->db->DBDriver === 'OCI8') { + $file = $builder->select('type_blob')->where('id', $id)->get()->getRow(); + $file = $file->type_blob->load(); + } else { + $file = $builder->select('type_blob')->where('id', $id)->get()->getRow(); + $file = $file->type_blob; + } + + $this->assertSame(strlen($fileContent), strlen($file)); + } } diff --git a/tests/system/Database/Live/SQLSRV/GetFieldDataTestCase.php b/tests/system/Database/Live/SQLSRV/GetFieldDataTestCase.php index bf00175c4fab..47aa8d108972 100644 --- a/tests/system/Database/Live/SQLSRV/GetFieldDataTestCase.php +++ b/tests/system/Database/Live/SQLSRV/GetFieldDataTestCase.php @@ -219,6 +219,13 @@ public function testGetFieldDataType(): void 'default' => null, ], 16 => (object) [ + 'name' => 'type_blob', + 'type' => 'varbinary', + 'max_length' => 'max', + 'nullable' => true, + 'default' => null, + ], + 17 => (object) [ 'name' => 'type_boolean', 'type' => 'bit', 'max_length' => null, diff --git a/user_guide_src/source/changelogs/v4.5.6.rst b/user_guide_src/source/changelogs/v4.5.6.rst index 569c5a542ecd..bf751a686135 100644 --- a/user_guide_src/source/changelogs/v4.5.6.rst +++ b/user_guide_src/source/changelogs/v4.5.6.rst @@ -41,7 +41,8 @@ Bugs Fixed - **Validation:** Fixed a bug where complex language strings were not properly handled. - **CURLRequest:** Added support for handling proxy responses using HTTP versions other than 1.1. - **Database:** Fixed a bug that caused ``Postgre\Connection::reconnect()`` method to throw an error when the connection had not yet been established. -- **Model** Fixed a bug that caused the ``Model::getIdValue()`` method to not correctly recognize the primary key in the ``Entity`` object if a data mapping for the primary key was used. +- **Model:** Fixed a bug that caused the ``Model::getIdValue()`` method to not correctly recognize the primary key in the ``Entity`` object if a data mapping for the primary key was used. +- **Database:** Fixed a bug in prepared statement to correctly handle binary data. See the repo's `CHANGELOG.md `_ diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst index b4cc0f978ff9..4a07b4ba8295 100644 --- a/user_guide_src/source/database/queries.rst +++ b/user_guide_src/source/database/queries.rst @@ -246,6 +246,8 @@ array through in the second parameter: .. literalinclude:: queries/018.php +.. note:: Currently, the only database that actually uses the array of option is SQLSRV. + Executing the Query =================== From 21145774834ae56600557dae81b5c574f2af0436 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 27 Dec 2024 23:24:05 +0800 Subject: [PATCH 2/5] refactor: fix warning on new static usage --- tests/_support/Entity/CustomUser.php | 4 ++-- utils/phpstan-baseline/loader.neon | 1 - utils/phpstan-baseline/new.static.neon | 8 -------- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 utils/phpstan-baseline/new.static.neon diff --git a/tests/_support/Entity/CustomUser.php b/tests/_support/Entity/CustomUser.php index 0ba0c73e451b..94a6ae3345ab 100644 --- a/tests/_support/Entity/CustomUser.php +++ b/tests/_support/Entity/CustomUser.php @@ -26,7 +26,7 @@ * @property string $name * @property Time|null $updated_at */ -class CustomUser +final class CustomUser { private function __construct( private readonly int $id, @@ -40,7 +40,7 @@ private function __construct( public static function reconstruct(array $data): static { - return new static( + return new self( $data['id'], $data['name'], $data['email'], diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 40d901a7ab2d..8118710b2257 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -43,7 +43,6 @@ includes: - missingType.parameter.neon - missingType.property.neon - missingType.return.neon - - new.static.neon - notIdentical.alwaysTrue.neon - nullCoalesce.expr.neon - nullCoalesce.property.neon diff --git a/utils/phpstan-baseline/new.static.neon b/utils/phpstan-baseline/new.static.neon deleted file mode 100644 index b6195e61eb0b..000000000000 --- a/utils/phpstan-baseline/new.static.neon +++ /dev/null @@ -1,8 +0,0 @@ -# total 1 error - -parameters: - ignoreErrors: - - - message: '#^Unsafe usage of new static\(\)\.$#' - count: 1 - path: ../../tests/_support/Entity/CustomUser.php From 19ad2b99cc0396963fc5ea801453605e9976644b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 28 Dec 2024 14:31:01 +0800 Subject: [PATCH 3/5] refactor: fix used void return type (#9341) --- system/Commands/ListCommands.php | 12 +++++++++--- tests/system/Log/LoggerTest.php | 7 ++++++- utils/phpstan-baseline/loader.neon | 1 - utils/phpstan-baseline/method.void.neon | 18 ------------------ 4 files changed, 15 insertions(+), 23 deletions(-) delete mode 100644 utils/phpstan-baseline/method.void.neon diff --git a/system/Commands/ListCommands.php b/system/Commands/ListCommands.php index 3411b103430d..8761e2bb7bbc 100644 --- a/system/Commands/ListCommands.php +++ b/system/Commands/ListCommands.php @@ -71,6 +71,8 @@ class ListCommands extends BaseCommand /** * Displays the help for the spark cli script itself. + * + * @return int */ public function run(array $params) { @@ -78,7 +80,7 @@ public function run(array $params) ksort($commands); // Check for 'simple' format - return array_key_exists('simple', $params) || CLI::getOption('simple') + return array_key_exists('simple', $params) || CLI::getOption('simple') === true ? $this->listSimple($commands) : $this->listFull($commands); } @@ -86,7 +88,7 @@ public function run(array $params) /** * Lists the commands with accompanying info. * - * @return void + * @return int */ protected function listFull(array $commands) { @@ -124,17 +126,21 @@ protected function listFull(array $commands) CLI::newLine(); } } + + return EXIT_SUCCESS; } /** * Lists the commands only. * - * @return void + * @return int */ protected function listSimple(array $commands) { foreach (array_keys($commands) as $title) { CLI::write($title); } + + return EXIT_SUCCESS; } } diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 9464d4d286fd..0db30a93070d 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -20,6 +20,8 @@ use CodeIgniter\Test\Mock\MockLogger as LoggerConfig; use Exception; use PHPUnit\Framework\Attributes\Group; +use ReflectionMethod; +use ReflectionNamedType; use Tests\Support\Log\Handlers\TestHandler; use TypeError; @@ -67,7 +69,10 @@ public function testLogAlwaysReturnsVoid(): void $logger = new Logger($config); - $this->assertNull($logger->log('debug', '')); + $refMethod = new ReflectionMethod($logger, 'log'); + $this->assertTrue($refMethod->hasReturnType()); + $this->assertInstanceOf(ReflectionNamedType::class, $refMethod->getReturnType()); + $this->assertSame('void', $refMethod->getReturnType()->getName()); } public function testLogActuallyLogs(): void diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 8118710b2257..1746fc32470a 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -37,7 +37,6 @@ includes: - method.impossibleType.neon - method.notFound.neon - method.unused.neon - - method.void.neon - missingType.callable.neon - missingType.iterableValue.neon - missingType.parameter.neon diff --git a/utils/phpstan-baseline/method.void.neon b/utils/phpstan-baseline/method.void.neon deleted file mode 100644 index 09d958a496e7..000000000000 --- a/utils/phpstan-baseline/method.void.neon +++ /dev/null @@ -1,18 +0,0 @@ -# total 3 errors - -parameters: - ignoreErrors: - - - message: '#^Result of method CodeIgniter\\Commands\\ListCommands\:\:listFull\(\) \(void\) is used\.$#' - count: 1 - path: ../../system/Commands/ListCommands.php - - - - message: '#^Result of method CodeIgniter\\Commands\\ListCommands\:\:listSimple\(\) \(void\) is used\.$#' - count: 1 - path: ../../system/Commands/ListCommands.php - - - - message: '#^Result of method CodeIgniter\\Log\\Logger\:\:log\(\) \(void\) is used\.$#' - count: 1 - path: ../../tests/system/Log/LoggerTest.php From 8cff0995de4a322c050d4451c2d22c70bfa1b073 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Sat, 28 Dec 2024 15:21:06 +0300 Subject: [PATCH 4/5] refactor: fix `phpstan` only boolean allowed (#9302) * refactor: Fix `phpstan` boolean errors * fix: Check predis response * refactor: Improve comparison with an empty string * dev: Update phpstan-baseline * fix: Revert comparison with null --- system/BaseModel.php | 6 +- system/CLI/CLI.php | 20 ++--- system/Cache/Handlers/BaseHandler.php | 2 +- system/Cache/Handlers/PredisHandler.php | 3 +- system/Commands/Server/Serve.php | 2 +- system/Commands/Utilities/Routes.php | 10 ++- system/Common.php | 8 +- system/Database/Forge.php | 2 +- system/Database/MigrationRunner.php | 12 +-- system/Database/MySQLi/Connection.php | 8 +- system/Database/SQLite3/Connection.php | 4 +- system/Email/Email.php | 6 +- system/Encryption/Handlers/OpenSSLHandler.php | 4 +- system/Filters/Filters.php | 4 +- system/HTTP/Files/FileCollection.php | 2 +- system/HTTP/OutgoingRequest.php | 2 +- system/HTTP/RedirectResponse.php | 5 +- system/HTTP/RequestTrait.php | 2 +- system/HTTP/ResponseTrait.php | 11 ++- system/HTTP/UserAgent.php | 14 ++-- system/Helpers/form_helper.php | 2 +- system/Helpers/text_helper.php | 2 +- system/HotReloader/HotReloader.php | 3 +- system/Model.php | 12 +-- system/RESTful/BaseResource.php | 2 +- system/Router/AutoRouter.php | 8 +- system/Router/RouteCollection.php | 10 +-- .../Handlers/Database/PostgreHandler.php | 4 +- system/Session/Handlers/MemcachedHandler.php | 2 +- system/Test/CIUnitTestCase.php | 2 +- system/Test/FeatureTestTrait.php | 4 +- system/Test/FilterTestTrait.php | 4 +- system/Traits/ConditionalTrait.php | 8 +- system/Validation/FileRules.php | 23 ++++-- system/View/Table.php | 2 +- tests/system/Email/EmailTest.php | 2 +- tests/system/Models/FindModelTest.php | 12 +-- .../booleanAnd.leftNotBoolean.neon | 63 -------------- .../booleanAnd.rightNotBoolean.neon | 43 ---------- .../booleanNot.exprNotBoolean.neon | 68 --------------- .../booleanOr.leftNotBoolean.neon | 13 --- .../booleanOr.rightNotBoolean.neon | 18 ---- .../codeigniter.superglobalAccessAssign.neon | 2 +- .../elseif.condNotBoolean.neon | 8 -- utils/phpstan-baseline/if.condNotBoolean.neon | 82 +------------------ utils/phpstan-baseline/loader.neon | 7 -- .../ternary.condNotBoolean.neon | 43 ---------- 47 files changed, 128 insertions(+), 448 deletions(-) delete mode 100644 utils/phpstan-baseline/booleanAnd.leftNotBoolean.neon delete mode 100644 utils/phpstan-baseline/booleanAnd.rightNotBoolean.neon delete mode 100644 utils/phpstan-baseline/booleanNot.exprNotBoolean.neon delete mode 100644 utils/phpstan-baseline/booleanOr.leftNotBoolean.neon delete mode 100644 utils/phpstan-baseline/booleanOr.rightNotBoolean.neon delete mode 100644 utils/phpstan-baseline/elseif.condNotBoolean.neon delete mode 100644 utils/phpstan-baseline/ternary.condNotBoolean.neon diff --git a/system/BaseModel.php b/system/BaseModel.php index 0d4a7b3979b3..05c5459d8c4b 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -639,7 +639,7 @@ public function findColumn(string $columnName) $resultSet = $this->doFindColumn($columnName); - return $resultSet ? array_column($resultSet, $columnName) : null; + return $resultSet !== null ? array_column($resultSet, $columnName) : null; } /** @@ -1137,7 +1137,7 @@ public function delete($id = null, bool $purge = false) throw new InvalidArgumentException('delete(): argument #1 ($id) should not be boolean.'); } - if ($id && (is_numeric($id) || is_string($id))) { + if (! in_array($id, [null, 0, '0'], true) && (is_numeric($id) || is_string($id))) { $id = [$id]; } @@ -1250,7 +1250,7 @@ public function errors(bool $forceDB = false) } // Do we have validation errors? - if (! $forceDB && ! $this->skipValidation && ($errors = $this->validation->getErrors())) { + if (! $forceDB && ! $this->skipValidation && ($errors = $this->validation->getErrors()) !== []) { return $errors; } diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 236e5b685fff..185f51e3635c 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -225,12 +225,12 @@ public static function prompt(string $field, $options = null, $validation = null $extraOutput = ''; $default = ''; - if ($validation && ! is_array($validation) && ! is_string($validation)) { + if (isset($validation) && ! is_array($validation) && ! is_string($validation)) { throw new InvalidArgumentException('$rules can only be of type string|array'); } if (! is_array($validation)) { - $validation = $validation ? explode('|', $validation) : []; + $validation = ($validation !== null) ? explode('|', $validation) : []; } if (is_string($options)) { @@ -441,7 +441,7 @@ protected static function validate(string $field, string $value, $rules): bool */ public static function print(string $text = '', ?string $foreground = null, ?string $background = null) { - if ($foreground || $background) { + if ((string) $foreground !== '' || (string) $background !== '') { $text = static::color($text, $foreground, $background); } @@ -457,7 +457,7 @@ public static function print(string $text = '', ?string $foreground = null, ?str */ public static function write(string $text = '', ?string $foreground = null, ?string $background = null) { - if ($foreground || $background) { + if ((string) $foreground !== '' || (string) $background !== '') { $text = static::color($text, $foreground, $background); } @@ -480,7 +480,7 @@ public static function error(string $text, string $foreground = 'light_red', ?st $stdout = static::$isColored; static::$isColored = static::hasColorSupport(STDERR); - if ($foreground || $background) { + if ($foreground !== '' || (string) $background !== '') { $text = static::color($text, $foreground, $background); } @@ -589,7 +589,7 @@ public static function color(string $text, string $foreground, ?string $backgrou throw CLIException::forInvalidColor('foreground', $foreground); } - if ($background !== null && ! array_key_exists($background, static::$background_colors)) { + if ((string) $background !== '' && ! array_key_exists($background, static::$background_colors)) { throw CLIException::forInvalidColor('background', $background); } @@ -637,7 +637,7 @@ private static function getColoredText(string $text, string $foreground, ?string { $string = "\033[" . static::$foreground_colors[$foreground] . 'm'; - if ($background !== null) { + if ((string) $background !== '') { $string .= "\033[" . static::$background_colors[$background] . 'm'; } @@ -654,7 +654,7 @@ private static function getColoredText(string $text, string $foreground, ?string */ public static function strlen(?string $string): int { - if ($string === null) { + if ((string) $string === '') { return 0; } @@ -768,7 +768,7 @@ public static function generateDimensions() // Look for the next lines ending in ": " // Searching for "Columns:" or "Lines:" will fail on non-English locales - if ($return === 0 && $output && preg_match('/:\s*(\d+)\n[^:]+:\s*(\d+)\n/', implode("\n", $output), $matches)) { + if ($return === 0 && $output !== [] && preg_match('/:\s*(\d+)\n[^:]+:\s*(\d+)\n/', implode("\n", $output), $matches)) { static::$height = (int) $matches[1]; static::$width = (int) $matches[2]; } @@ -835,7 +835,7 @@ public static function showProgress($thisStep = 1, int $totalSteps = 10) */ public static function wrap(?string $string = null, int $max = 0, int $padLeft = 0): string { - if ($string === null || $string === '') { + if ((string) $string === '') { return ''; } diff --git a/system/Cache/Handlers/BaseHandler.php b/system/Cache/Handlers/BaseHandler.php index 43d316f87b0d..2e35864f5aba 100644 --- a/system/Cache/Handlers/BaseHandler.php +++ b/system/Cache/Handlers/BaseHandler.php @@ -67,7 +67,7 @@ public static function validateKey($key, $prefix = ''): string } $reserved = config(Cache::class)->reservedCharacters ?? self::RESERVED_CHARACTERS; - if ($reserved && strpbrk($key, $reserved) !== false) { + if ($reserved !== '' && strpbrk($key, $reserved) !== false) { throw new InvalidArgumentException('Cache key contains reserved characters ' . $reserved); } diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index 59e35aa4208f..fc0185033d64 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -19,6 +19,7 @@ use Exception; use Predis\Client; use Predis\Collection\Iterator\Keyspace; +use Predis\Response\Status; /** * Predis cache handler @@ -121,7 +122,7 @@ public function save(string $key, $value, int $ttl = 60) return false; } - if (! $this->redis->hmset($key, ['__ci_type' => $dataType, '__ci_value' => $value])) { + if (! $this->redis->hmset($key, ['__ci_type' => $dataType, '__ci_value' => $value]) instanceof Status) { return false; } diff --git a/system/Commands/Server/Serve.php b/system/Commands/Server/Serve.php index 82e58998a732..594e4e587e27 100644 --- a/system/Commands/Server/Serve.php +++ b/system/Commands/Server/Serve.php @@ -110,7 +110,7 @@ public function run(array $params) // to ensure our environment is set and it simulates basic mod_rewrite. passthru($php . ' -S ' . $host . ':' . $port . ' -t ' . $docroot . ' ' . $rewrite, $status); - if ($status && $this->portOffset < $this->tries) { + if ($status !== EXIT_SUCCESS && $this->portOffset < $this->tries) { $this->portOffset++; $this->run($params); diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index 9adcc1bc39e7..a0f81f6b42a0 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -86,7 +86,7 @@ public function run(array $params) $host = $params['host'] ?? null; // Set HTTP_HOST - if ($host) { + if ($host !== null) { $request = service('request'); $_SERVER = $request->getServer(); $_SERVER['HTTP_HOST'] = $host; @@ -96,7 +96,7 @@ public function run(array $params) $collection = service('routes')->loadRoutes(); // Reset HTTP_HOST - if ($host) { + if ($host !== null) { unset($_SERVER['HTTP_HOST']); } @@ -139,7 +139,9 @@ public function run(array $params) $autoRoutes = $autoRouteCollector->get(); // Check for Module Routes. - if ($routingConfig = config(Routing::class)) { + $routingConfig = config(Routing::class); + + if ($routingConfig instanceof Routing) { foreach ($routingConfig->moduleRoutes as $uri => $namespace) { $autoRouteCollector = new AutoRouteCollectorImproved( $namespace, @@ -188,7 +190,7 @@ public function run(array $params) usort($tbody, static fn ($handler1, $handler2) => strcmp($handler1[3], $handler2[3])); } - if ($host) { + if ($host !== null) { CLI::write('Host: ' . $host); } diff --git a/system/Common.php b/system/Common.php index 85db03f2870c..b647c9d247ad 100644 --- a/system/Common.php +++ b/system/Common.php @@ -441,7 +441,7 @@ function esc($data, string $context = 'html', ?string $encoding = null) $escaper = new Escaper($encoding); } - if ($encoding && $escaper->getEncoding() !== $encoding) { + if ($encoding !== null && $escaper->getEncoding() !== $encoding) { $escaper = new Escaper($encoding); } @@ -739,13 +739,13 @@ function lang(string $line, array $args = [], ?string $locale = null) // Get active locale $activeLocale = $language->getLocale(); - if ($locale && $locale !== $activeLocale) { + if ((string) $locale !== '' && $locale !== $activeLocale) { $language->setLocale($locale); } $lines = $language->getLine($line, $args); - if ($locale && $locale !== $activeLocale) { + if ((string) $locale !== '' && $locale !== $activeLocale) { // Reset to active locale $language->setLocale($activeLocale); } @@ -849,7 +849,7 @@ function redirect(?string $route = null): RedirectResponse { $response = service('redirectresponse'); - if ($route !== null) { + if ((string) $route !== '') { return $response->route($route); } diff --git a/system/Database/Forge.php b/system/Database/Forge.php index d2cfde6bf104..fc9aa54ec169 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -650,7 +650,7 @@ public function dropTable(string $tableName, bool $ifExists = false, bool $casca return false; } - if ($this->db->DBPrefix && str_starts_with($tableName, $this->db->DBPrefix)) { + if ($this->db->DBPrefix !== '' && str_starts_with($tableName, $this->db->DBPrefix)) { $tableName = substr($tableName, strlen($this->db->DBPrefix)); } diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index cf736171a7cf..4a39f13562e8 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -389,7 +389,7 @@ public function force(string $path, string $namespace, ?string $group = null) */ public function findMigrations(): array { - $namespaces = $this->namespace ? [$this->namespace] : array_keys(service('autoloader')->getNamespace()); + $namespaces = $this->namespace !== null ? [$this->namespace] : array_keys(service('autoloader')->getNamespace()); $migrations = []; foreach ($namespaces as $namespace) { @@ -524,7 +524,7 @@ protected function getMigrationNumber(string $migration): string { preg_match($this->regex, $migration, $matches); - return count($matches) ? $matches[1] : '0'; + return $matches !== [] ? $matches[1] : '0'; } /** @@ -539,7 +539,7 @@ protected function getMigrationName(string $migration): string { preg_match($this->regex, $migration, $matches); - return count($matches) ? $matches[2] : ''; + return $matches !== [] ? $matches[2] : ''; } /** @@ -645,7 +645,7 @@ public function getHistory(string $group = 'default'): array } // If a namespace was specified then use it - if ($this->namespace) { + if ($this->namespace !== null) { $builder->where('namespace', $this->namespace); } @@ -700,7 +700,7 @@ public function getLastBatch(): int ->get() ->getResultObject(); - $batch = is_array($batch) && count($batch) + $batch = is_array($batch) && $batch !== [] ? end($batch)->batch : 0; @@ -725,7 +725,7 @@ public function getBatchStart(int $batch): string ->get() ->getResultObject(); - return count($migration) ? $migration[0]->version : '0'; + return $migration !== [] ? $migration[0]->version : '0'; } /** diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index b40db946894d..f98f51fb3e19 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -193,7 +193,7 @@ public function connect(bool $persistent = false) $clientFlags )) { // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails - if (($clientFlags & MYSQLI_CLIENT_SSL) && version_compare($this->mysqli->client_info, 'mysqlnd 5.7.3', '<=') + if (($clientFlags & MYSQLI_CLIENT_SSL) !== 0 && version_compare($this->mysqli->client_info, 'mysqlnd 5.7.3', '<=') && empty($this->mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value) ) { $this->mysqli->close(); @@ -395,7 +395,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n { $sql = 'SHOW TABLES FROM ' . $this->escapeIdentifier($this->database); - if ($tableName !== null) { + if ((string) $tableName !== '') { return $sql . ' LIKE ' . $this->escape($tableName); } @@ -462,7 +462,9 @@ protected function _indexData(string $table): array throw new DatabaseException(lang('Database.failGetIndexData')); } - if (! $indexes = $query->getResultArray()) { + $indexes = $query->getResultArray(); + + if ($indexes === []) { return []; } diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index a1a03eff61f5..577e4b24ab76 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -89,7 +89,7 @@ public function connect(bool $persistent = false) $this->database = WRITEPATH . $this->database; } - $sqlite = (! $this->password) + $sqlite = (! isset($this->password) || $this->password !== '') ? new SQLite3($this->database) : new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password); @@ -194,7 +194,7 @@ protected function _escapeString(string $str): string */ protected function _listTables(bool $prefixLimit = false, ?string $tableName = null): string { - if ($tableName !== null) { + if ((string) $tableName !== '') { return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\'' . ' AND "NAME" NOT LIKE \'sqlite!_%\' ESCAPE \'!\'' . ' AND "NAME" LIKE ' . $this->escape($tableName); diff --git a/system/Email/Email.php b/system/Email/Email.php index b82779eb891d..51f610f6556c 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -485,7 +485,7 @@ public function setFrom($from, $name = '', $returnPath = null) if ($this->validate) { $this->validateEmail($this->stringToArray($from)); - if ($returnPath) { + if ($returnPath !== null) { $this->validateEmail($this->stringToArray($returnPath)); } } @@ -1233,7 +1233,9 @@ protected function buildMessage() $this->headerStr .= $hdr; } - static::strlen($body) && $body .= $this->newline . $this->newline; + if (static::strlen($body) > 0) { + $body .= $this->newline . $this->newline; + } $body .= $this->getMimeMessage() . $this->newline . $this->newline . '--' . $lastBoundary . $this->newline diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index f3b62c64a498..9745160b8003 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -82,7 +82,7 @@ class OpenSSLHandler extends BaseHandler public function encrypt($data, $params = null) { // Allow key override - if ($params) { + if ($params !== null) { $this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params; } @@ -118,7 +118,7 @@ public function encrypt($data, $params = null) public function decrypt($data, $params = null) { // Allow key override - if ($params) { + if ($params !== null) { $this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params; } diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 1255e0c4055d..fd252fe1fa26 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -557,7 +557,7 @@ public function enableFilters(array $names, string $when = 'before') */ public function getArguments(?string $key = null) { - return $key === null ? $this->arguments : $this->arguments[$key]; + return ((string) $key === '') ? $this->arguments : $this->arguments[$key]; } // -------------------------------------------------------------------- @@ -674,7 +674,7 @@ protected function processMethods() */ protected function processFilters(?string $uri = null) { - if (! isset($this->config->filters) || ! $this->config->filters) { + if (! isset($this->config->filters) || $this->config->filters === []) { return; } diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 079d5e73114f..add2c3c03f9c 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -253,7 +253,7 @@ protected function getValueDotNotationSyntax(array $index, array $value) { $currentIndex = array_shift($index); - if (isset($currentIndex) && is_array($index) && $index && is_array($value[$currentIndex]) && $value[$currentIndex]) { + if (isset($currentIndex) && is_array($index) && $index !== [] && array_key_exists($currentIndex, $value) && is_array($value[$currentIndex])) { return $this->getValueDotNotationSyntax($index, $value[$currentIndex]); } diff --git a/system/HTTP/OutgoingRequest.php b/system/HTTP/OutgoingRequest.php index 27e473a59ad1..e62f07241558 100644 --- a/system/HTTP/OutgoingRequest.php +++ b/system/HTTP/OutgoingRequest.php @@ -64,7 +64,7 @@ private function getHostFromUri(URI $uri): string { $host = $uri->getHost(); - return $host . ($uri->getPort() ? ':' . $uri->getPort() : ''); + return $host . ($uri->getPort() > 0 ? ':' . $uri->getPort() : ''); } /** diff --git a/system/HTTP/RedirectResponse.php b/system/HTTP/RedirectResponse.php index c8c76607b651..206b1de07c67 100644 --- a/system/HTTP/RedirectResponse.php +++ b/system/HTTP/RedirectResponse.php @@ -115,9 +115,8 @@ private function withErrors(): self { $validation = service('validation'); - if ($validation->getErrors()) { - $session = service('session'); - $session->setFlashdata('_ci_validation_errors', $validation->getErrors()); + if ($validation->getErrors() !== []) { + service('session')->setFlashdata('_ci_validation_errors', $validation->getErrors()); } return $this; diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 51de3ea5c0fc..dfa4b663dbaf 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -59,7 +59,7 @@ trait RequestTrait */ public function getIPAddress(): string { - if ($this->ipAddress) { + if ($this->ipAddress !== '') { return $this->ipAddress; } diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 45f07d186170..97ef4927d35c 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -123,18 +123,21 @@ public function setDate(DateTime $date) */ public function setLink(PagerInterface $pager) { - $links = ''; + $links = ''; + $previous = $pager->getPreviousPageURI(); - if ($previous = $pager->getPreviousPageURI()) { + if (is_string($previous) && $previous !== '') { $links .= '<' . $pager->getPageURI($pager->getFirstPage()) . '>; rel="first",'; $links .= '<' . $previous . '>; rel="prev"'; } - if (($next = $pager->getNextPageURI()) && $previous) { + $next = $pager->getNextPageURI(); + + if (is_string($next) && $next !== '' && is_string($previous) && $previous !== '') { $links .= ','; } - if ($next) { + if (is_string($next) && $next !== '') { $links .= '<' . $next . '>; rel="next",'; $links .= '<' . $pager->getPageURI($pager->getLastPage()) . '>; rel="last"'; } diff --git a/system/HTTP/UserAgent.php b/system/HTTP/UserAgent.php index 6a5104779a92..ec4d17438284 100644 --- a/system/HTTP/UserAgent.php +++ b/system/HTTP/UserAgent.php @@ -125,7 +125,7 @@ public function isBrowser(?string $key = null): bool } // No need to be specific, it's a browser - if ($key === null) { + if ((string) $key === '') { return true; } @@ -143,7 +143,7 @@ public function isRobot(?string $key = null): bool } // No need to be specific, it's a robot - if ($key === null) { + if ((string) $key === '') { return true; } @@ -161,7 +161,7 @@ public function isMobile(?string $key = null): bool } // No need to be specific, it's a mobile - if ($key === null) { + if ((string) $key === '') { return true; } @@ -289,7 +289,7 @@ protected function compileData() */ protected function setPlatform(): bool { - if (is_array($this->config->platforms) && $this->config->platforms) { + if (is_array($this->config->platforms) && $this->config->platforms !== []) { foreach ($this->config->platforms as $key => $val) { if (preg_match('|' . preg_quote($key, '|') . '|i', $this->agent)) { $this->platform = $val; @@ -309,7 +309,7 @@ protected function setPlatform(): bool */ protected function setBrowser(): bool { - if (is_array($this->config->browsers) && $this->config->browsers) { + if (is_array($this->config->browsers) && $this->config->browsers !== []) { foreach ($this->config->browsers as $key => $val) { if (preg_match('|' . $key . '.*?([0-9\.]+)|i', $this->agent, $match)) { $this->isBrowser = true; @@ -330,7 +330,7 @@ protected function setBrowser(): bool */ protected function setRobot(): bool { - if (is_array($this->config->robots) && $this->config->robots) { + if (is_array($this->config->robots) && $this->config->robots !== []) { foreach ($this->config->robots as $key => $val) { if (preg_match('|' . preg_quote($key, '|') . '|i', $this->agent)) { $this->isRobot = true; @@ -350,7 +350,7 @@ protected function setRobot(): bool */ protected function setMobile(): bool { - if (is_array($this->config->mobiles) && $this->config->mobiles) { + if (is_array($this->config->mobiles) && $this->config->mobiles !== []) { foreach ($this->config->mobiles as $key => $val) { if (false !== (stripos($this->agent, $key))) { $this->isMobile = true; diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index 58cd828e3faa..c3e2c83de0a6 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -788,7 +788,7 @@ function parse_form_attributes($attributes, array $default): string if (! is_bool($val)) { if ($key === 'value') { $val = esc($val); - } elseif ($key === 'name' && ! strlen($default['name'])) { + } elseif ($key === 'name' && $default['name'] === '') { continue; } $att .= $key . '="' . $val . '"' . ($key === array_key_last($default) ? '' : ' '); diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 3de105736f57..dcc21126a5e5 100644 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -741,7 +741,7 @@ function excerpt(string $text, ?string $phrase = null, int $radius = 100, string $count = ++$count + strlen($s); } - $ellPre = $phrase ? $ellipsis : ''; + $ellPre = $phrase !== null ? $ellipsis : ''; return str_replace(' ', ' ', $ellPre . $prev . $phrase . $post . $ellipsis); } diff --git a/system/HotReloader/HotReloader.php b/system/HotReloader/HotReloader.php index 6dfd0fcf66a9..305e641af04e 100644 --- a/system/HotReloader/HotReloader.php +++ b/system/HotReloader/HotReloader.php @@ -37,7 +37,7 @@ public function run(): void $appHash = $hasher->hash(); while (true) { - if (connection_status() !== CONNECTION_NORMAL || connection_aborted()) { + if (connection_status() !== CONNECTION_NORMAL || connection_aborted() === 1) { break; } @@ -50,6 +50,7 @@ public function run(): void $this->sendEvent('reload', ['time' => date('Y-m-d H:i:s')]); break; } + if (mt_rand(1, 10) > 8) { $this->sendEvent('ping', ['time' => date('Y-m-d H:i:s')]); } diff --git a/system/Model.php b/system/Model.php index fb1ebceda516..98e3be0b1f68 100644 --- a/system/Model.php +++ b/system/Model.php @@ -317,13 +317,13 @@ protected function doFirst() if ($this->tempUseSoftDeletes) { $builder->where($this->table . '.' . $this->deletedField, null); - } elseif ($this->useSoftDeletes && ($builder->QBGroupBy === []) && $this->primaryKey) { + } elseif ($this->useSoftDeletes && ($builder->QBGroupBy === []) && $this->primaryKey !== '') { $builder->groupBy($this->table . '.' . $this->primaryKey); } // Some databases, like PostgreSQL, need order // information to consistently return correct results. - if ($builder->QBGroupBy && ($builder->QBOrderBy === []) && $this->primaryKey) { + if ($builder->QBGroupBy !== [] && ($builder->QBOrderBy === []) && $this->primaryKey !== '') { $builder->orderBy($this->table . '.' . $this->primaryKey, 'asc'); } @@ -443,7 +443,7 @@ protected function doUpdate($id = null, $row = null): bool $builder = $this->builder(); - if ($id) { + if (! in_array($id, [null, '', 0, '0', []], true)) { $builder = $builder->whereIn($this->table . '.' . $this->primaryKey, $id); } @@ -496,7 +496,7 @@ protected function doDelete($id = null, bool $purge = false) $set = []; $builder = $this->builder(); - if ($id) { + if (! in_array($id, [null, '', 0, '0', []], true)) { $builder = $builder->whereIn($this->primaryKey, $id); } @@ -690,7 +690,7 @@ public function builder(?string $table = null) // Check for an existing Builder if ($this->builder instanceof BaseBuilder) { // Make sure the requested table matches the builder - if ($table && $this->builder->getTable() !== $table) { + if ((string) $table !== '' && $this->builder->getTable() !== $table) { return $this->db->table($table); } @@ -704,7 +704,7 @@ public function builder(?string $table = null) throw ModelException::forNoPrimaryKey(static::class); } - $table = ($table === null || $table === '') ? $this->table : $table; + $table = ((string) $table === '') ? $this->table : $table; // Ensure we have a good db connection if (! $this->db instanceof BaseConnection) { diff --git a/system/RESTful/BaseResource.php b/system/RESTful/BaseResource.php index 0360bdb12fc5..f2e171c8319e 100644 --- a/system/RESTful/BaseResource.php +++ b/system/RESTful/BaseResource.php @@ -61,7 +61,7 @@ public function initController(RequestInterface $request, ResponseInterface $res */ public function setModel($which = null) { - if ($which) { + if ($which !== null) { $this->model = is_object($which) ? $which : null; $this->modelName = is_object($which) ? null : $which; } diff --git a/system/Router/AutoRouter.php b/system/Router/AutoRouter.php index bb47bf96c89a..ce40f5cdc406 100644 --- a/system/Router/AutoRouter.php +++ b/system/Router/AutoRouter.php @@ -105,7 +105,7 @@ public function getRoute(string $uri, string $httpVerb): array if ($httpVerb !== 'CLI') { $controller = '\\' . $this->defaultNamespace; - $controller .= $this->directory ? str_replace('/', '\\', $this->directory) : ''; + $controller .= $this->directory !== null ? str_replace('/', '\\', $this->directory) : ''; $controller .= $controllerName; $controller = strtolower($controller); @@ -244,7 +244,7 @@ private function isValidSegment(string $segment): bool */ public function setDirectory(?string $dir = null, bool $append = false, bool $validate = true) { - if ($dir === null || $dir === '') { + if ((string) $dir === '') { $this->directory = null; return; @@ -260,7 +260,7 @@ public function setDirectory(?string $dir = null, bool $append = false, bool $va } } - if (! $append || ($this->directory === null || $this->directory === '')) { + if (! $append || ((string) $this->directory === '')) { $this->directory = trim($dir, '/') . '/'; } else { $this->directory .= trim($dir, '/') . '/'; @@ -275,7 +275,7 @@ public function setDirectory(?string $dir = null, bool $append = false, bool $va */ public function directory(): string { - return ($this->directory !== null && $this->directory !== '') ? $this->directory : ''; + return ((string) $this->directory !== '') ? $this->directory : ''; } private function controllerName(): string diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index ad5c01a4858f..2dbaba05e4cd 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -560,7 +560,7 @@ public function shouldAutoRoute(): bool */ public function getRoutes(?string $verb = null, bool $includeWildcard = true): array { - if ($verb === null || $verb === '') { + if ((string) $verb === '') { $verb = $this->getHTTPVerb(); } @@ -609,7 +609,7 @@ public function getRoutesOptions(?string $from = null, ?string $verb = null): ar { $options = $this->loadRoutesOptions($verb); - return $from ? $options[$from] ?? [] : $options; + return ((string) $from !== '') ? $options[$from] ?? [] : $options; } /** @@ -779,7 +779,7 @@ public function group(string $name, ...$params) $callback = array_pop($params); - if ($params && is_array($params[0])) { + if ($params !== [] && is_array($params[0])) { $options = array_shift($params); if (isset($options['filter'])) { @@ -1416,14 +1416,14 @@ private function replaceLocale(string $route, ?string $locale = null): string } // Check invalid locale - if ($locale !== null) { + if ((string) $locale !== '') { $config = config(App::class); if (! in_array($locale, $config->supportedLocales, true)) { $locale = null; } } - if ($locale === null) { + if ((string) $locale === '') { $locale = service('request')->getLocale(); } diff --git a/system/Session/Handlers/Database/PostgreHandler.php b/system/Session/Handlers/Database/PostgreHandler.php index b92ab1e57323..e999f356decd 100644 --- a/system/Session/Handlers/Database/PostgreHandler.php +++ b/system/Session/Handlers/Database/PostgreHandler.php @@ -75,7 +75,7 @@ public function gc($max_lifetime) protected function lockSession(string $sessionID): bool { $arg = "hashtext('{$sessionID}')" . ($this->matchIP ? ", hashtext('{$this->ipAddress}')" : ''); - if ($this->db->simpleQuery("SELECT pg_advisory_lock({$arg})")) { + if ($this->db->simpleQuery("SELECT pg_advisory_lock({$arg})") !== false) { $this->lock = $arg; return true; @@ -93,7 +93,7 @@ protected function releaseLock(): bool return true; } - if ($this->db->simpleQuery("SELECT pg_advisory_unlock({$this->lock})")) { + if ($this->db->simpleQuery("SELECT pg_advisory_unlock({$this->lock})") !== false) { $this->lock = false; return true; diff --git a/system/Session/Handlers/MemcachedHandler.php b/system/Session/Handlers/MemcachedHandler.php index 79bb4ca4613f..83a5d334ed85 100644 --- a/system/Session/Handlers/MemcachedHandler.php +++ b/system/Session/Handlers/MemcachedHandler.php @@ -267,7 +267,7 @@ protected function lockSession(string $sessionID): bool $attempt = 0; do { - if ($this->memcached->get($lockKey)) { + if ($this->memcached->get($lockKey) !== false) { sleep(1); continue; diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 62c0fff83844..9e82ddb4f6dd 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -238,7 +238,7 @@ protected function setUp(): void { parent::setUp(); - if (! $this->app) { + if (! $this->app instanceof CodeIgniter) { $this->app = $this->createApplication(); } diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index 083313dfa7e2..13522d8758f3 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -189,7 +189,9 @@ public function call(string $method, string $path, ?array $params = null) $request = $this->setRequestBody($request, $params); // Initialize the RouteCollection - if (! $routes = $this->routes) { + $routes = $this->routes; + + if ($routes !== []) { $routes = service('routes')->loadRoutes(); } diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 5837e6e658a6..d004ec22c5c1 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -221,7 +221,9 @@ protected function getFiltersForRoute(string $route, string $position): array $this->filters->reset(); - if ($routeFilters = $this->collection->getFiltersForRoute($route)) { + $routeFilters = $this->collection->getFiltersForRoute($route); + + if ($routeFilters !== []) { $this->filters->enableFilters($routeFilters, $position); } diff --git a/system/Traits/ConditionalTrait.php b/system/Traits/ConditionalTrait.php index c927a6815a8d..a778e9375a36 100644 --- a/system/Traits/ConditionalTrait.php +++ b/system/Traits/ConditionalTrait.php @@ -29,9 +29,9 @@ trait ConditionalTrait */ public function when($condition, callable $callback, ?callable $defaultCallback = null): self { - if ($condition) { + if ($condition !== '' && $condition !== false && $condition !== null) { $callback($this, $condition); - } elseif ($defaultCallback) { + } elseif ($defaultCallback !== null) { $defaultCallback($this); } @@ -52,9 +52,9 @@ public function when($condition, callable $callback, ?callable $defaultCallback */ public function whenNot($condition, callable $callback, ?callable $defaultCallback = null): self { - if (! $condition) { + if ($condition === '' || $condition === null || $condition === false || $condition === '0') { $callback($this, $condition); - } elseif ($defaultCallback) { + } elseif ($defaultCallback !== null) { $defaultCallback($this); } diff --git a/system/Validation/FileRules.php b/system/Validation/FileRules.php index 78d0ce521809..058b15739eef 100644 --- a/system/Validation/FileRules.php +++ b/system/Validation/FileRules.php @@ -52,7 +52,9 @@ public function __construct(?RequestInterface $request = null) */ public function uploaded(?string $blank, string $name): bool { - if (! ($files = $this->request->getFileMultiple($name))) { + $files = $this->request->getFileMultiple($name); + + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } @@ -86,12 +88,15 @@ public function max_size(?string $blank, string $params): bool // Grab the file name off the top of the $params // after we split it. $paramArray = explode(',', $params); + if (count($paramArray) !== 2) { throw new InvalidArgumentException('Invalid max_size parameter: "' . $params . '"'); } - $name = array_shift($paramArray); - if (! ($files = $this->request->getFileMultiple($name))) { + $name = array_shift($paramArray); + $files = $this->request->getFileMultiple($name); + + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } @@ -126,8 +131,9 @@ public function is_image(?string $blank, string $params): bool // after we split it. $params = explode(',', $params); $name = array_shift($params); + $files = $this->request->getFileMultiple($name); - if (! ($files = $this->request->getFileMultiple($name))) { + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } @@ -161,8 +167,9 @@ public function mime_in(?string $blank, string $params): bool // after we split it. $params = explode(',', $params); $name = array_shift($params); + $files = $this->request->getFileMultiple($name); - if (! ($files = $this->request->getFileMultiple($name))) { + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } @@ -192,8 +199,9 @@ public function ext_in(?string $blank, string $params): bool // after we split it. $params = explode(',', $params); $name = array_shift($params); + $files = $this->request->getFileMultiple($name); - if (! ($files = $this->request->getFileMultiple($name))) { + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } @@ -224,8 +232,9 @@ public function max_dims(?string $blank, string $params): bool // after we split it. $params = explode(',', $params); $name = array_shift($params); + $files = $this->request->getFileMultiple($name); - if (! ($files = $this->request->getFileMultiple($name))) { + if ($files === [] || $files === null) { $files = [$this->request->getFile($name)]; } diff --git a/system/View/Table.php b/system/View/Table.php index 60ccc509f9ae..9eb29578a6da 100644 --- a/system/View/Table.php +++ b/system/View/Table.php @@ -333,7 +333,7 @@ public function generate($tableData = null) $out = $this->template['table_open'] . $this->newline; // Add any caption here - if ($this->caption) { + if (isset($this->caption) && $this->caption !== '') { $out .= '' . $this->caption . '' . $this->newline; } diff --git a/tests/system/Email/EmailTest.php b/tests/system/Email/EmailTest.php index 99918122d8cf..389b657e573a 100644 --- a/tests/system/Email/EmailTest.php +++ b/tests/system/Email/EmailTest.php @@ -44,7 +44,7 @@ public static function provideEmailSendWithClearance(): iterable } /** - * @param mixed $autoClear + * @param bool $autoClear */ #[DataProvider('provideEmailSendWithClearance')] public function testEmailSendWithClearance($autoClear): void diff --git a/tests/system/Models/FindModelTest.php b/tests/system/Models/FindModelTest.php index b15857d4aaaf..43fb96d76b53 100644 --- a/tests/system/Models/FindModelTest.php +++ b/tests/system/Models/FindModelTest.php @@ -180,8 +180,8 @@ public function testFirst(): void } /** - * @param mixed $groupBy - * @param mixed $total + * @param bool $groupBy + * @param int $total */ #[DataProvider('provideFirstAggregate')] public function testFirstAggregate($groupBy, $total): void @@ -215,8 +215,8 @@ public static function provideFirstAggregate(): iterable } /** - * @param mixed $aggregate - * @param mixed $groupBy + * @param bool $aggregate + * @param bool $groupBy */ #[DataProvider('provideAggregateAndGroupBy')] public function testFirstRespectsSoftDeletes($aggregate, $groupBy): void @@ -260,8 +260,8 @@ public function testFirstRespectsSoftDeletes($aggregate, $groupBy): void } /** - * @param mixed $aggregate - * @param mixed $groupBy + * @param bool $aggregate + * @param bool $groupBy */ #[DataProvider('provideAggregateAndGroupBy')] public function testFirstRecoverTempUseSoftDeletes($aggregate, $groupBy): void diff --git a/utils/phpstan-baseline/booleanAnd.leftNotBoolean.neon b/utils/phpstan-baseline/booleanAnd.leftNotBoolean.neon deleted file mode 100644 index 856ad498e2e6..000000000000 --- a/utils/phpstan-baseline/booleanAnd.leftNotBoolean.neon +++ /dev/null @@ -1,63 +0,0 @@ -# total 12 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in &&, array\|int\|string\|null given on the left side\.$#' - count: 1 - path: ../../system/BaseModel.php - - - - message: '#^Only booleans are allowed in &&, array\|string\|null given on the left side\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in &&, string given on the left side\.$#' - count: 1 - path: ../../system/Cache/Handlers/BaseHandler.php - - - - message: '#^Only booleans are allowed in &&, int given on the left side\.$#' - count: 1 - path: ../../system/Commands/Server/Serve.php - - - - message: '#^Only booleans are allowed in &&, string\|null given on the left side\.$#' - count: 3 - path: ../../system/Common.php - - - - message: '#^Only booleans are allowed in &&, string given on the left side\.$#' - count: 1 - path: ../../system/Database/Forge.php - - - - message: '#^Only booleans are allowed in &&, int given on the left side\.$#' - count: 1 - path: ../../system/Database/MySQLi/Connection.php - - - - message: '#^Only booleans are allowed in &&, int given on the left side\.$#' - count: 1 - path: ../../system/Email/Email.php - - - - message: '#^Only booleans are allowed in &&, string\|null given on the left side\.$#' - count: 1 - path: ../../system/HTTP/Response.php - - - - message: '#^Only booleans are allowed in &&, array given on the left side\.$#' - count: 1 - path: ../../system/Model.php - - - - message: '#^Only booleans are allowed in &&, string\|null given on the left side\.$#' - count: 1 - path: ../../system/Model.php - - - - message: '#^Only booleans are allowed in &&, array\ given on the left side\.$#' - count: 1 - path: ../../system/Router/RouteCollection.php diff --git a/utils/phpstan-baseline/booleanAnd.rightNotBoolean.neon b/utils/phpstan-baseline/booleanAnd.rightNotBoolean.neon deleted file mode 100644 index 8be1c9e657d0..000000000000 --- a/utils/phpstan-baseline/booleanAnd.rightNotBoolean.neon +++ /dev/null @@ -1,43 +0,0 @@ -# total 8 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in &&, array\ given on the right side\.$#' - count: 1 - path: ../../system/BaseModel.php - - - - message: '#^Only booleans are allowed in &&, list\ given on the right side\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in &&, int\<0, max\> given on the right side\.$#' - count: 1 - path: ../../system/Database/MigrationRunner.php - - - - message: '#^Only booleans are allowed in &&, string given on the right side\.$#' - count: 1 - path: ../../system/Email/Email.php - - - - message: '#^Only booleans are allowed in &&, array\ given on the right side\.$#' - count: 2 - path: ../../system/HTTP/Files/FileCollection.php - - - - message: '#^Only booleans are allowed in &&, string\|null given on the right side\.$#' - count: 1 - path: ../../system/HTTP/Response.php - - - - message: '#^Only booleans are allowed in &&, array\ given on the right side\.$#' - count: 4 - path: ../../system/HTTP/UserAgent.php - - - - message: '#^Only booleans are allowed in &&, string given on the right side\.$#' - count: 2 - path: ../../system/Model.php diff --git a/utils/phpstan-baseline/booleanNot.exprNotBoolean.neon b/utils/phpstan-baseline/booleanNot.exprNotBoolean.neon deleted file mode 100644 index 41a36091437c..000000000000 --- a/utils/phpstan-baseline/booleanNot.exprNotBoolean.neon +++ /dev/null @@ -1,68 +0,0 @@ -# total 13 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#' - count: 1 - path: ../../system/Cache/Handlers/PredisHandler.php - - - - message: '#^Only booleans are allowed in a negated boolean, TWhenNot given\.$#' - count: 1 - path: ../../system/Database/BaseBuilder.php - - - - message: '#^Only booleans are allowed in a negated boolean, array given\.$#' - count: 1 - path: ../../system/Database/MySQLi/Connection.php - - - - message: '#^Only booleans are allowed in a negated boolean, string given\.$#' - count: 1 - path: ../../system/Database/SQLite3/Connection.php - - - - message: '#^Only booleans are allowed in a negated boolean, array\\>\> given\.$#' - count: 1 - path: ../../system/Filters/Filters.php - - - - message: '#^Only booleans are allowed in a negated boolean, int\<0, max\> given\.$#' - count: 1 - path: ../../system/Helpers/form_helper.php - - - - message: '#^Only booleans are allowed in a negated boolean, CodeIgniter\\CodeIgniter given\.$#' - count: 1 - path: ../../system/Test/CIUnitTestCase.php - - - - message: '#^Only booleans are allowed in a negated boolean, array\|null given\.$#' - count: 6 - path: ../../system/Validation/FileRules.php - - - - message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#' - count: 1 - path: ../../tests/system/Email/EmailTest.php - - - - message: '#^Only booleans are allowed in a negated boolean, CodeIgniter\\Router\\RouteCollection\|null given\.$#' - count: 1 - path: ../../tests/system/HomeTest.php - - - - message: '#^Only booleans are allowed in a negated boolean, mixed given\.$#' - count: 2 - path: ../../tests/system/Models/FindModelTest.php - - - - message: '#^Only booleans are allowed in a negated boolean, CodeIgniter\\Router\\RouteCollection\|null given\.$#' - count: 1 - path: ../../tests/system/Test/FeatureTestAutoRoutingImprovedTest.php - - - - message: '#^Only booleans are allowed in a negated boolean, CodeIgniter\\Router\\RouteCollection\|null given\.$#' - count: 1 - path: ../../tests/system/Test/FeatureTestTraitTest.php diff --git a/utils/phpstan-baseline/booleanOr.leftNotBoolean.neon b/utils/phpstan-baseline/booleanOr.leftNotBoolean.neon deleted file mode 100644 index bb6d0e1d3324..000000000000 --- a/utils/phpstan-baseline/booleanOr.leftNotBoolean.neon +++ /dev/null @@ -1,13 +0,0 @@ -# total 2 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in \|\|, string given on the left side\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in \|\|, string\|null given on the left side\.$#' - count: 2 - path: ../../system/CLI/CLI.php diff --git a/utils/phpstan-baseline/booleanOr.rightNotBoolean.neon b/utils/phpstan-baseline/booleanOr.rightNotBoolean.neon deleted file mode 100644 index cca548646c48..000000000000 --- a/utils/phpstan-baseline/booleanOr.rightNotBoolean.neon +++ /dev/null @@ -1,18 +0,0 @@ -# total 3 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in \|\|, string\|null given on the right side\.$#' - count: 3 - path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in \|\|, int given on the right side\.$#' - count: 1 - path: ../../system/HotReloader/HotReloader.php - - - - message: '#^Only booleans are allowed in \|\|, mixed given on the right side\.$#' - count: 1 - path: ../../tests/system/Models/FindModelTest.php diff --git a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon index 2b08524179cb..4eae1fef60ee 100644 --- a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon +++ b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon @@ -3,7 +3,7 @@ parameters: ignoreErrors: - - message: '#^Assigning non\-falsy\-string directly on offset ''HTTP_HOST'' of \$_SERVER is discouraged\.$#' + message: '#^Assigning string directly on offset ''HTTP_HOST'' of \$_SERVER is discouraged\.$#' count: 1 path: ../../system/Commands/Utilities/Routes.php diff --git a/utils/phpstan-baseline/elseif.condNotBoolean.neon b/utils/phpstan-baseline/elseif.condNotBoolean.neon deleted file mode 100644 index 81f9d151f114..000000000000 --- a/utils/phpstan-baseline/elseif.condNotBoolean.neon +++ /dev/null @@ -1,8 +0,0 @@ -# total 1 error - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in an elseif condition, \(callable\)\|null given\.$#' - count: 2 - path: ../../system/Database/BaseBuilder.php diff --git a/utils/phpstan-baseline/if.condNotBoolean.neon b/utils/phpstan-baseline/if.condNotBoolean.neon index 3acc4f2b460b..6e9b4b56f3fb 100644 --- a/utils/phpstan-baseline/if.condNotBoolean.neon +++ b/utils/phpstan-baseline/if.condNotBoolean.neon @@ -1,4 +1,4 @@ -# total 17 errors +# total 1 error parameters: ignoreErrors: @@ -6,83 +6,3 @@ parameters: message: '#^Only booleans are allowed in an if condition, mixed given\.$#' count: 1 path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in an if condition, Config\\Routing given\.$#' - count: 1 - path: ../../system/Commands/Utilities/Routes.php - - - - message: '#^Only booleans are allowed in an if condition, string\|null given\.$#' - count: 3 - path: ../../system/Commands/Utilities/Routes.php - - - - message: '#^Only booleans are allowed in an if condition, TWhen given\.$#' - count: 1 - path: ../../system/Database/BaseBuilder.php - - - - message: '#^Only booleans are allowed in an if condition, string\|null given\.$#' - count: 1 - path: ../../system/Database/MigrationRunner.php - - - - message: '#^Only booleans are allowed in an if condition, string\|null given\.$#' - count: 1 - path: ../../system/Email/Email.php - - - - message: '#^Only booleans are allowed in an if condition, array\|string\|null given\.$#' - count: 2 - path: ../../system/Encryption/Handlers/OpenSSLHandler.php - - - - message: '#^Only booleans are allowed in an if condition, array\ given\.$#' - count: 1 - path: ../../system/HTTP/RedirectResponse.php - - - - message: '#^Only booleans are allowed in an if condition, string given\.$#' - count: 1 - path: ../../system/HTTP/Request.php - - - - message: '#^Only booleans are allowed in an if condition, string\|null given\.$#' - count: 2 - path: ../../system/HTTP/Response.php - - - - message: '#^Only booleans are allowed in an if condition, array\|int\|string\|null given\.$#' - count: 2 - path: ../../system/Model.php - - - - message: '#^Only booleans are allowed in an if condition, object\|string\|null given\.$#' - count: 1 - path: ../../system/RESTful/BaseResource.php - - - - message: '#^Only booleans are allowed in an if condition, mixed given\.$#' - count: 2 - path: ../../system/Session/Handlers/Database/PostgreHandler.php - - - - message: '#^Only booleans are allowed in an if condition, mixed given\.$#' - count: 1 - path: ../../system/Session/Handlers/MemcachedHandler.php - - - - message: '#^Only booleans are allowed in an if condition, string\|null given\.$#' - count: 1 - path: ../../system/View/Table.php - - - - message: '#^Only booleans are allowed in an if condition, mixed given\.$#' - count: 5 - path: ../../tests/system/Models/FindModelTest.php - - - - message: '#^Only booleans are allowed in an if condition, list\ given\.$#' - count: 1 - path: ../../tests/system/Test/FilterTestTraitTest.php diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 1746fc32470a..789d5ef7e1ef 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,12 +1,7 @@ includes: - argument.type.neon - assign.propertyType.neon - - booleanAnd.leftNotBoolean.neon - booleanAnd.rightAlwaysTrue.neon - - booleanAnd.rightNotBoolean.neon - - booleanNot.exprNotBoolean.neon - - booleanOr.leftNotBoolean.neon - - booleanOr.rightNotBoolean.neon - class.notFound.neon - codeigniter.cacheHandlerInstance.neon - codeigniter.configArgumentInstanceof.neon @@ -18,7 +13,6 @@ includes: - codeigniter.superglobalAccessAssign.neon - codeigniter.unknownServiceMethod.neon - deadCode.unreachable.neon - - elseif.condNotBoolean.neon - empty.notAllowed.neon - empty.property.neon - expr.resultUnused.neon @@ -60,7 +54,6 @@ includes: - return.type.neon - return.unusedType.neon - staticMethod.notFound.neon - - ternary.condNotBoolean.neon - ternary.shortNotAllowed.neon - unset.offset.neon - varTag.type.neon diff --git a/utils/phpstan-baseline/ternary.condNotBoolean.neon b/utils/phpstan-baseline/ternary.condNotBoolean.neon deleted file mode 100644 index 97d5bc785dac..000000000000 --- a/utils/phpstan-baseline/ternary.condNotBoolean.neon +++ /dev/null @@ -1,43 +0,0 @@ -# total 8 errors - -parameters: - ignoreErrors: - - - message: '#^Only booleans are allowed in a ternary operator condition, array\|null given\.$#' - count: 1 - path: ../../system/BaseModel.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, int\<0, max\> given\.$#' - count: 3 - path: ../../system/Database/MigrationRunner.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#' - count: 1 - path: ../../system/Database/MigrationRunner.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, int\|null given\.$#' - count: 1 - path: ../../system/HTTP/OutgoingRequest.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#' - count: 1 - path: ../../system/Helpers/text_helper.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#' - count: 1 - path: ../../system/Router/AutoRouter.php - - - - message: '#^Only booleans are allowed in a ternary operator condition, string\|null given\.$#' - count: 1 - path: ../../system/Router/RouteCollection.php From ee4ee987b16aa84e5ba797c91d3bdc6a2fde443c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 28 Dec 2024 22:16:32 +0700 Subject: [PATCH 5/5] refactor: enable instanceof and strictBooleans rector set (#9339) * refactor: enable instanceof and strictBooleans rector set * refactor: bump to rector 2.0.4 * refactor: clean condition check * refactor: revert ThirdParty change * refactor: re-run phpstan baseline * refactor: fix never empty array on Image * refactor: avoid repetitive call pg_last_error() * refactor: pg_last_error() always returns string * refactor: use return empty string on pg_last_error() got empty "0" * refactor: various compare !== 1 on preg_match() * refactor: use falsy check on getenv() * refactor: more !== 1 compare on preg_match() * refactor: use empty string check on guessExtension * refactor: run cs fix * refactor: more !== 1 compare on preg_match() * use direct result of pg_last_error() * refactor: use str_contains() over strpos on Forge * refactor: fix unused variable * refactor: check empty string on ResponseTrait * refactor: more preg_match() and empty string only check * refactor: compare to 0 on preg_match_all() * refactor: re-run rector * refactor: preg_match_all() likely less to return false --- app/Views/errors/cli/error_exception.php | 2 +- composer.json | 2 +- rector.php | 8 +--- system/CLI/CLI.php | 2 +- system/Cache/Handlers/FileHandler.php | 2 +- .../ControllerMethodReader.php | 2 +- .../Routes/ControllerMethodReader.php | 2 +- system/Config/DotEnv.php | 2 +- system/Config/Services.php | 8 ++-- system/Cookie/Cookie.php | 2 +- system/Database/BaseBuilder.php | 6 +-- system/Database/BaseConnection.php | 2 +- system/Database/Database.php | 2 +- system/Database/MigrationRunner.php | 2 +- system/Database/MySQLi/Forge.php | 4 +- system/Database/Postgre/Connection.php | 2 +- system/Email/Email.php | 4 +- system/HTTP/Files/UploadedFile.php | 4 +- system/HTTP/ResponseTrait.php | 6 +-- system/HTTP/SiteURI.php | 2 +- system/Helpers/filesystem_helper.php | 2 +- system/Helpers/form_helper.php | 2 +- system/Helpers/html_helper.php | 6 +-- system/I18n/TimeTrait.php | 6 +-- system/Images/Image.php | 3 +- system/Router/RouteCollection.php | 4 +- system/Session/Handlers/FileHandler.php | 2 +- system/Session/Handlers/MemcachedHandler.php | 4 +- system/Session/Session.php | 2 +- system/Test/CIUnitTestCase.php | 2 +- system/Typography/Typography.php | 2 +- system/Validation/Rules.php | 4 +- system/Validation/StrictRules/Rules.php | 4 +- system/Validation/Validation.php | 2 +- system/View/Parser.php | 4 +- .../ternary.shortNotAllowed.neon | 45 +++---------------- ...nderscoreToCamelCaseVariableNameRector.php | 2 +- 37 files changed, 63 insertions(+), 99 deletions(-) diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php index 9f47d25141d2..2bf1459d4094 100644 --- a/app/Views/errors/cli/error_exception.php +++ b/app/Views/errors/cli/error_exception.php @@ -52,7 +52,7 @@ $args = implode(', ', array_map(static fn ($value) => match (true) { is_object($value) => 'Object(' . $value::class . ')', - is_array($value) => count($value) ? '[...]' : '[]', + is_array($value) => $value !== [] ? '[...]' : '[]', $value === null => 'null', // return the lowercased version default => var_export($value, true), }, array_values($error['args'] ?? []))); diff --git a/composer.json b/composer.json index 879a42267043..ec9f29ec2d1b 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "2.0.3", + "rector/rector": "2.0.4", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { diff --git a/rector.php b/rector.php index e7c98746eb86..ee8621691862 100644 --- a/rector.php +++ b/rector.php @@ -38,7 +38,6 @@ use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; -use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector; @@ -56,11 +55,8 @@ return RectorConfig::configure() ->withPhpSets(php81: true) - ->withPreparedSets(deadCode: true) - ->withSets([ - PHPUnitSetList::PHPUNIT_CODE_QUALITY, - PHPUnitSetList::PHPUNIT_100, - ]) + ->withPreparedSets(deadCode: true, instanceOf: true, strictBooleans: true, phpunitCodeQuality: true) + ->withComposerBased(phpunit: true) ->withParallel(120, 8, 10) ->withCache( // Github action cache or local diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 185f51e3635c..0b5b01b179aa 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -348,7 +348,7 @@ public static function promptByMultipleKeys(string $text, array $options): array // return the prompt again if $input contain(s) non-numeric character, except a comma. // And if max from $options less than max from input, // it means user tried to access null value in $options - if (! $pattern || $maxOptions < $maxInput) { + if ($pattern === 0 || $maxOptions < $maxInput) { static::error('Please select correctly.'); CLI::newLine(); diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index fd0630a9982c..525616a71068 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -308,7 +308,7 @@ protected function deleteFiles(string $path, bool $delDir = false, bool $htdocs if ($filename !== '.' && $filename !== '..') { if (is_dir($path . DIRECTORY_SEPARATOR . $filename) && $filename[0] !== '.') { $this->deleteFiles($path . DIRECTORY_SEPARATOR . $filename, $delDir, $htdocs, $_level + 1); - } elseif (! $htdocs || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { + } elseif (! $htdocs || preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename) !== 1) { @unlink($path . DIRECTORY_SEPARATOR . $filename); } } diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php index e08a16ff7a60..2755a389ffc3 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php @@ -221,7 +221,7 @@ private function getRouteForDefaultController( if ($classShortname === $defaultController) { $pattern = '#' . preg_quote(lcfirst($defaultController), '#') . '\z#'; $routeWithoutController = rtrim(preg_replace($pattern, '', $uriByClass), '/'); - $routeWithoutController = $routeWithoutController ?: '/'; + $routeWithoutController = $routeWithoutController !== '' && $routeWithoutController !== '0' ? $routeWithoutController : '/'; [$params, $routeParams] = $this->getParameters($method); diff --git a/system/Commands/Utilities/Routes/ControllerMethodReader.php b/system/Commands/Utilities/Routes/ControllerMethodReader.php index c443b669465a..b40a832b4f48 100644 --- a/system/Commands/Utilities/Routes/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/ControllerMethodReader.php @@ -161,7 +161,7 @@ private function getRouteWithoutController( $pattern = '#' . preg_quote(lcfirst($defaultController), '#') . '\z#'; $routeWithoutController = rtrim(preg_replace($pattern, '', $uriByClass), '/'); - $routeWithoutController = $routeWithoutController ?: '/'; + $routeWithoutController = $routeWithoutController !== '' && $routeWithoutController !== '0' ? $routeWithoutController : '/'; return [[ 'route' => $routeWithoutController, diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index db7152fd09d5..d4a7d9e87389 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -94,7 +94,7 @@ public function parse(): ?array */ protected function setVariable(string $name, string $value = '') { - if (! getenv($name, true)) { + if (getenv($name, true) === false) { putenv("{$name}={$value}"); } diff --git a/system/Config/Services.php b/system/Config/Services.php index 61026de4292c..aa8c180a3388 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -345,7 +345,7 @@ public static function image(?string $handler = null, ?Images $config = null, bo $config ??= config(Images::class); assert($config instanceof Images); - $handler = $handler ?: $config->defaultHandler; + $handler = $handler !== null && $handler !== '' && $handler !== '0' ? $handler : $config->defaultHandler; $class = $config->handlers[$handler]; return new $class($config); @@ -385,7 +385,7 @@ public static function language(?string $locale = null, bool $getShared = true) } // Use '?:' for empty string check - $locale = $locale ?: $requestLocale; + $locale = $locale !== null && $locale !== '' && $locale !== '0' ? $locale : $requestLocale; return new Language($locale); } @@ -484,7 +484,7 @@ public static function parser(?string $viewPath = null, ?ViewConfig $config = nu return static::getSharedInstance('parser', $viewPath, $config); } - $viewPath = $viewPath ?: (new Paths())->viewDirectory; + $viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory; $config ??= config(ViewConfig::class); return new Parser($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger')); @@ -503,7 +503,7 @@ public static function renderer(?string $viewPath = null, ?ViewConfig $config = return static::getSharedInstance('renderer', $viewPath, $config); } - $viewPath = $viewPath ?: (new Paths())->viewDirectory; + $viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory; $config ??= config(ViewConfig::class); return new View($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger')); diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index 01b10db19b65..d75cce26ac09 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -482,7 +482,7 @@ public function withNeverExpiring() */ public function withPath(?string $path) { - $path = $path ?: self::$defaults['path']; + $path = $path !== null && $path !== '' && $path !== '0' ? $path : self::$defaults['path']; $this->validatePrefix($this->prefix, $this->secure, $path, $this->domain); $cookie = clone $this; diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index e52baa39f570..e738a331d608 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1736,7 +1736,7 @@ public function countAllResults(bool $reset = true) // Restore the LIMIT setting $this->QBLimit = $limit; - $row = ! $result instanceof ResultInterface ? null : $result->getRow(); + $row = $result instanceof ResultInterface ? $result->getRow() : null; if (empty($row)) { return 0; @@ -3167,11 +3167,11 @@ protected function compileWhereHaving(string $qbKey): string $op = $this->getOperator($condition); if ( $op === false - || ! preg_match( + || preg_match( '/^(\(?)(.*)(' . preg_quote($op, '/') . ')\s*(.*(?queryClass; + $queryClass = $queryClass !== '' && $queryClass !== '0' ? $queryClass : $this->queryClass; if (empty($this->connID)) { $this->initialize(); diff --git a/system/Database/Database.php b/system/Database/Database.php index 23b6cd0f8d16..e09dcdd27481 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -96,7 +96,7 @@ protected function parseDSN(array $params): array { $dsn = parse_url($params['DSN']); - if (! $dsn) { + if ($dsn === 0 || $dsn === '' || $dsn === '0' || $dsn === [] || $dsn === false || $dsn === null) { throw new InvalidArgumentException('Your DSN connection string is invalid.'); } diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index 4a39f13562e8..13919c785372 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -450,7 +450,7 @@ protected function migrationFromFile(string $path, string $namespace) $filename = basename($path, '.php'); - if (! preg_match($this->regex, $filename)) { + if (preg_match($this->regex, $filename) !== 1) { return false; } diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 3bde0c518daf..c47ff4ded393 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -116,11 +116,11 @@ protected function _createTableAttributes(array $attributes): string } } - if ($this->db->charset !== '' && ! strpos($sql, 'CHARACTER SET') && ! strpos($sql, 'CHARSET')) { + if ($this->db->charset !== '' && ! str_contains($sql, 'CHARACTER SET') && ! str_contains($sql, 'CHARSET')) { $sql .= ' DEFAULT CHARACTER SET = ' . $this->db->escapeString($this->db->charset); } - if ($this->db->DBCollat !== '' && ! strpos($sql, 'COLLATE')) { + if ($this->db->DBCollat !== '' && ! str_contains($sql, 'COLLATE')) { $sql .= ' COLLATE = ' . $this->db->escapeString($this->db->DBCollat); } diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 2826ab1bf53c..4ce2b0763536 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -463,7 +463,7 @@ public function error(): array { return [ 'code' => '', - 'message' => pg_last_error($this->connID) ?: '', + 'message' => pg_last_error($this->connID), ]; } diff --git a/system/Email/Email.php b/system/Email/Email.php index 51f610f6556c..5d420cc2e99c 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -495,7 +495,7 @@ public function setFrom($from, $name = '', $returnPath = null) if ($name !== '') { // only use Q encoding if there are characters that would require it - if (! preg_match('/[\200-\377]/', $name)) { + if (preg_match('/[\200-\377]/', $name) !== 1) { $name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"'; } else { $name = $this->prepQEncoding($name); @@ -532,7 +532,7 @@ public function setReplyTo($replyto, $name = '') $this->tmpArchive['replyName'] = $name; // only use Q encoding if there are characters that would require it - if (! preg_match('/[\200-\377]/', $name)) { + if (preg_match('/[\200-\377]/', $name) !== 1) { $name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"'; } else { $name = $this->prepQEncoding($name); diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 78643aa7166e..c17a9e5af8e5 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -302,7 +302,9 @@ public function getTempName(): string */ public function getExtension(): string { - return $this->guessExtension() ?: $this->getClientExtension(); + $guessExtension = $this->guessExtension(); + + return $guessExtension !== '' ? $guessExtension : $this->getClientExtension(); } /** diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 97ef4927d35c..eaf60f2b38b4 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -569,7 +569,7 @@ public function getCookieStore() */ public function hasCookie(string $name, ?string $value = null, string $prefix = ''): bool { - $prefix = $prefix ?: Cookie::setDefaults()['prefix']; // to retain BC + $prefix = $prefix !== '' ? $prefix : Cookie::setDefaults()['prefix']; // to retain BC return $this->cookieStore->has($name, $prefix, $value); } @@ -589,7 +589,7 @@ public function getCookie(?string $name = null, string $prefix = '') } try { - $prefix = $prefix ?: Cookie::setDefaults()['prefix']; // to retain BC + $prefix = $prefix !== '' ? $prefix : Cookie::setDefaults()['prefix']; // to retain BC return $this->cookieStore->get($name, $prefix); } catch (CookieException $e) { @@ -610,7 +610,7 @@ public function deleteCookie(string $name = '', string $domain = '', string $pat return $this; } - $prefix = $prefix ?: Cookie::setDefaults()['prefix']; // to retain BC + $prefix = $prefix !== '' ? $prefix : Cookie::setDefaults()['prefix']; // to retain BC $prefixed = $prefix . $name; $store = $this->cookieStore; diff --git a/system/HTTP/SiteURI.php b/system/HTTP/SiteURI.php index 91b14bc05456..2be70a7773ef 100644 --- a/system/HTTP/SiteURI.php +++ b/system/HTTP/SiteURI.php @@ -421,7 +421,7 @@ public function siteUrl($relativePath = '', ?string $scheme = null, ?App $config $relativePath = $this->stringifyRelativePath($relativePath); // Check current host. - $host = ! $config instanceof App ? $this->getHost() : null; + $host = $config instanceof App ? null : $this->getHost(); $config ??= config(App::class); diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 4b0b49be6464..d5f2d974e4ad 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -166,7 +166,7 @@ function delete_files(string $path, bool $delDir = false, bool $htdocs = false, continue; } - if (! $htdocs || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { + if (! $htdocs || preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename) !== 1) { $isDir = $object->isDir(); if ($isDir && $delDir) { rmdir($object->getPathname()); diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index c3e2c83de0a6..7e11388841f4 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -62,7 +62,7 @@ function form_open(string $action = '', $attributes = [], array $hidden = []): s // Add CSRF field if enabled, but leave it out for GET requests and requests to external websites $before = service('filters')->getFilters()['before']; - if ((in_array('csrf', $before, true) || array_key_exists('csrf', $before)) && str_contains($action, base_url()) && ! stripos($form, 'method="get"')) { + if ((in_array('csrf', $before, true) || array_key_exists('csrf', $before)) && str_contains($action, base_url()) && stripos($form, 'method="get"') === false) { $form .= csrf_field($csrfId ?? null); } diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 30733acd5175..3eb55a6d5150 100644 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -112,7 +112,7 @@ function img($src = '', bool $indexPage = false, $attributes = ''): string $img = ' $v) { - if ($k === 'src' && ! preg_match('#^([a-z]+:)?//#i', $v)) { + if ($k === 'src' && preg_match('#^([a-z]+:)?//#i', $v) !== 1) { if ($indexPage) { $script .= 'src="' . site_url($v) . '" '; } else { @@ -252,7 +252,7 @@ function link_tag( $href = $href['href'] ?? ''; } - if (! preg_match('#^([a-z]+:)?//#i', $href)) { + if (preg_match('#^([a-z]+:)?//#i', $href) !== 1) { $attributes['href'] = $indexPage ? site_url($href) : slash_item('baseURL') . $href; } else { $attributes['href'] = $href; diff --git a/system/I18n/TimeTrait.php b/system/I18n/TimeTrait.php index fefb2fc544a3..354b7542e755 100644 --- a/system/I18n/TimeTrait.php +++ b/system/I18n/TimeTrait.php @@ -73,7 +73,7 @@ trait TimeTrait */ public function __construct(?string $time = null, $timezone = null, ?string $locale = null) { - $this->locale = $locale ?: Locale::getDefault(); + $this->locale = $locale !== null && $locale !== '' && $locale !== '0' ? $locale : Locale::getDefault(); $time ??= ''; @@ -958,7 +958,7 @@ public function sameAs($testTime, ?string $timezone = null): bool if ($testTime instanceof DateTimeInterface) { $testTime = $testTime->format('Y-m-d H:i:s'); } elseif (is_string($testTime)) { - $timezone = $timezone ?: $this->timezone; + $timezone = $timezone !== null && $timezone !== '' && $timezone !== '0' ? $timezone : $this->timezone; $timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); $testTime = new DateTime($testTime, $timezone); $testTime = $testTime->format('Y-m-d H:i:s'); @@ -1108,7 +1108,7 @@ public function getUTCObject($time, ?string $timezone = null) if ($time instanceof self) { $time = $time->toDateTime(); } elseif (is_string($time)) { - $timezone = $timezone ?: $this->timezone; + $timezone = $timezone !== null && $timezone !== '' && $timezone !== '0' ? $timezone : $this->timezone; $timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); $time = new DateTime($time, $timezone); } diff --git a/system/Images/Image.php b/system/Images/Image.php index ec6d4b8fa5c0..55754e339535 100644 --- a/system/Images/Image.php +++ b/system/Images/Image.php @@ -102,8 +102,9 @@ public function copy(string $targetPath, ?string $targetName = null, int $perms public function getProperties(bool $return = false) { $path = $this->getPathname(); + $vals = getimagesize($path); - if (! $vals = getimagesize($path)) { + if ($vals === false) { throw ImageException::forFileNotSupported(); } diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 2dbaba05e4cd..13cbba449989 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1329,7 +1329,7 @@ protected function fillRouteParams(string $from, ?array $params = null): string $patterns = $matches[0]; foreach ($patterns as $index => $pattern) { - if (! preg_match('#^' . $pattern . '$#u', $params[$index])) { + if (preg_match('#^' . $pattern . '$#u', $params[$index]) !== 1) { throw RouterException::forInvalidParameterType(); } @@ -1391,7 +1391,7 @@ protected function buildReverseRoute(string $from, array $params): string // or maybe $placeholder is not a placeholder, but a regex. $pattern = $this->placeholders[$placeholderName] ?? $placeholder; - if (! preg_match('#^' . $pattern . '$#u', (string) $params[$index])) { + if (preg_match('#^' . $pattern . '$#u', (string) $params[$index]) !== 1) { throw RouterException::forInvalidParameterType(); } diff --git a/system/Session/Handlers/FileHandler.php b/system/Session/Handlers/FileHandler.php index 4dbec779526a..6931ab1c581f 100644 --- a/system/Session/Handlers/FileHandler.php +++ b/system/Session/Handlers/FileHandler.php @@ -290,7 +290,7 @@ public function gc($max_lifetime) while (($file = readdir($directory)) !== false) { // If the filename doesn't match this pattern, it's either not a session file or is not ours - if (! preg_match($pattern, $file) + if (preg_match($pattern, $file) !== 1 || ! is_file($this->savePath . DIRECTORY_SEPARATOR . $file) || ($mtime = filemtime($this->savePath . DIRECTORY_SEPARATOR . $file)) === false || $mtime > $ts diff --git a/system/Session/Handlers/MemcachedHandler.php b/system/Session/Handlers/MemcachedHandler.php index 83a5d334ed85..e651808a8ba8 100644 --- a/system/Session/Handlers/MemcachedHandler.php +++ b/system/Session/Handlers/MemcachedHandler.php @@ -93,12 +93,12 @@ public function open($path, $name): bool } if ( - ! preg_match_all( + preg_match_all( '#,?([^,:]+)\:(\d{1,5})(?:\:(\d+))?#', $this->savePath, $matches, PREG_SET_ORDER - ) + ) === 0 ) { $this->memcached = null; $this->logger->error('Session: Invalid Memcached save path format: ' . $this->savePath); diff --git a/system/Session/Session.php b/system/Session/Session.php index 60e4dbef4101..a9b7bd4fa5fe 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -234,7 +234,7 @@ public function start() // Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers if (isset($_COOKIE[$this->config->cookieName]) - && (! is_string($_COOKIE[$this->config->cookieName]) || ! preg_match('#\A' . $this->sidRegexp . '\z#', $_COOKIE[$this->config->cookieName])) + && (! is_string($_COOKIE[$this->config->cookieName]) || preg_match('#\A' . $this->sidRegexp . '\z#', $_COOKIE[$this->config->cookieName]) !== 1) ) { unset($_COOKIE[$this->config->cookieName]); } diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 9e82ddb4f6dd..467e3a61bdf7 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -374,7 +374,7 @@ public function assertLogContains(string $level, string $logMessage, string $mes { $this->assertTrue( TestLogger::didLog($level, $logMessage, false), - $message ?: sprintf( + $message !== '' ? $message : sprintf( 'Failed asserting that logs have a record of message containing "%s" with level "%s".', $logMessage, $level diff --git a/system/Typography/Typography.php b/system/Typography/Typography.php index c8ca5131171c..145ff68f1193 100644 --- a/system/Typography/Typography.php +++ b/system/Typography/Typography.php @@ -171,7 +171,7 @@ public function autoTypography(string $str, bool $reduceLinebreaks = false): str } // No opening block level tag? Add it if needed. - if (! preg_match('/^\s*<(?:' . $this->blockElements . ')/i', $str)) { + if (preg_match('/^\s*<(?:' . $this->blockElements . ')/i', $str) !== 1) { $str = preg_replace('/^(.*?)<(' . $this->blockElements . ')/i', '

$1

<$2', $str); } diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 715e2e51c7e1..7f2f0bd941ec 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -140,7 +140,7 @@ public function is_not_unique($str, string $field, array $data): bool if ( $whereField !== null && $whereField !== '' && $whereValue !== null && $whereValue !== '' - && ! preg_match('/^\{(\w+)\}$/', $whereValue) + && preg_match('/^\{(\w+)\}$/', $whereValue) !== 1 ) { $row = $row->where($whereField, $whereValue); } @@ -198,7 +198,7 @@ public function is_unique($str, string $field, array $data): bool if ( $ignoreField !== null && $ignoreField !== '' && $ignoreValue !== null && $ignoreValue !== '' - && ! preg_match('/^\{(\w+)\}$/', $ignoreValue) + && preg_match('/^\{(\w+)\}$/', $ignoreValue) !== 1 ) { $row = $row->where("{$ignoreField} !=", $ignoreValue); } diff --git a/system/Validation/StrictRules/Rules.php b/system/Validation/StrictRules/Rules.php index ec02a4e0a0ac..c9b98c479875 100644 --- a/system/Validation/StrictRules/Rules.php +++ b/system/Validation/StrictRules/Rules.php @@ -164,7 +164,7 @@ public function is_not_unique($str, string $field, array $data): bool if ( $whereField !== null && $whereField !== '' && $whereValue !== null && $whereValue !== '' - && ! preg_match('/^\{(\w+)\}$/', $whereValue) + && preg_match('/^\{(\w+)\}$/', $whereValue) !== 1 ) { $row = $row->where($whereField, $whereValue); } @@ -224,7 +224,7 @@ public function is_unique($str, string $field, array $data): bool if ( $ignoreField !== null && $ignoreField !== '' && $ignoreValue !== null && $ignoreValue !== '' - && ! preg_match('/^\{(\w+)\}$/', $ignoreValue) + && preg_match('/^\{(\w+)\}$/', $ignoreValue) !== 1 ) { $row = $row->where("{$ignoreField} !=", $ignoreValue); } diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index a942a32bceea..c00329d670bb 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -181,7 +181,7 @@ public function run(?array $data = null, ?string $group = null, $dbGroup = null) ); // if keys not found - $values = $values ?: [$field => null]; + $values = $values !== [] ? $values : [$field => null]; } else { $values = dot_array_search($field, $data); } diff --git a/system/View/Parser.php b/system/View/Parser.php index 8a26cf825d3f..08fec93e16fc 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -613,7 +613,7 @@ public function shouldAddEscaping(string $key) $escape = false; } // If no `esc` filter is found, then we'll need to add one. - elseif (! preg_match('/\s+esc/u', $key)) { + elseif (preg_match('/\s+esc/u', $key) !== 1) { $escape = 'html'; } @@ -691,7 +691,7 @@ protected function parsePlugins(string $template) * $matches[1] = all parameters string in opening tag * $matches[2] = content between the tags to send to the plugin. */ - if (! preg_match_all($pattern, $template, $matches, PREG_SET_ORDER)) { + if (preg_match_all($pattern, $template, $matches, PREG_SET_ORDER) === 0) { continue; } diff --git a/utils/phpstan-baseline/ternary.shortNotAllowed.neon b/utils/phpstan-baseline/ternary.shortNotAllowed.neon index 15e447d499c0..a3dfc431cd94 100644 --- a/utils/phpstan-baseline/ternary.shortNotAllowed.neon +++ b/utils/phpstan-baseline/ternary.shortNotAllowed.neon @@ -1,4 +1,4 @@ -# total 34 errors +# total 27 errors parameters: ignoreErrors: @@ -17,16 +17,6 @@ parameters: count: 1 path: ../../system/Commands/Utilities/Namespaces.php - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php - - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/Commands/Utilities/Routes/ControllerMethodReader.php - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 2 @@ -35,23 +25,8 @@ parameters: - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 4 - path: ../../system/Config/Services.php - - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 5 path: ../../system/Cookie/Cookie.php - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/Database/BaseConnection.php - - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/Database/Postgre/Connection.php - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 1 @@ -79,12 +54,7 @@ parameters: - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/HTTP/Files/UploadedFile.php - - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 5 + count: 2 path: ../../system/HTTP/Response.php - @@ -94,12 +64,12 @@ parameters: - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 4 + count: 1 path: ../../system/I18n/Time.php - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 4 + count: 1 path: ../../system/I18n/TimeLegacy.php - @@ -117,11 +87,6 @@ parameters: count: 1 path: ../../system/Session/Session.php - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/Test/CIUnitTestCase.php - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 2 @@ -129,7 +94,7 @@ parameters: - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 2 + count: 1 path: ../../system/Validation/Validation.php - diff --git a/utils/src/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/src/Rector/UnderscoreToCamelCaseVariableNameRector.php index 1e1469c7f615..93817c45bbd5 100644 --- a/utils/src/Rector/UnderscoreToCamelCaseVariableNameRector.php +++ b/utils/src/Rector/UnderscoreToCamelCaseVariableNameRector.php @@ -178,7 +178,7 @@ private function updateDocblock(string $variableName, string $camelCaseName, ?Fu return; } - if (! preg_match(sprintf(self::PARAM_NAME_REGEX, $variableName), $docCommentText)) { + if (preg_match(sprintf(self::PARAM_NAME_REGEX, $variableName), $docCommentText) !== 1) { return; }