diff --git a/.gitattributes b/.gitattributes index 4b9a73d9d0e7..e2219ef90a4e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,31 +5,33 @@ # git files .gitattributes export-ignore -.gitignore export-ignore +.gitignore export-ignore -# Don't give admin files -.github/ export-ignore -admin/ export-ignore -contributing/ export-ignore -.editorconfig export-ignore -.nojekyll export-ignore +# admin files +.github/ export-ignore +admin/ export-ignore +contributing/ export-ignore +.editorconfig export-ignore CODE_OF_CONDUCT.md export-ignore -CONTRIBUTING.md export-ignore +CONTRIBUTING.md export-ignore -# They don't want our test files -tests/AutoReview/ export-ignore -tests/system/ export-ignore -utils/ export-ignore -deptrac.yaml export-ignore -rector.php export-ignore -phpunit.xml.dist export-ignore -phpstan-baseline.neon.dist export-ignore -phpstan.neon.dist export-ignore -phpstan-bootstrap.php export-ignore -.php-cs-fixer.dist.php export-ignore -.php-cs-fixer.no-header.php export-ignore +# contributor/development files +tests/ export-ignore +utils/ export-ignore +.php-cs-fixer.dist.php export-ignore +.php-cs-fixer.no-header.php export-ignore .php-cs-fixer.user-guide.php export-ignore +deptrac.yaml export-ignore +phpstan-baseline.neon.dist export-ignore +phpstan-bootstrap.php export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore +psalm_autoload.php export-ignore +psalm-baseline.php export-ignore +psalm.xml export-ignore +rector.php export-ignore -# The source user guide, either +# source user guide user_guide_src/ export-ignore +.nojekyll export-ignore phpdoc.dist.xml export-ignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f9393d2b215..f0147f72b57b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,37 @@ # Changelog +## [v4.4.8](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.8) (2024-04-07) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.7...v4.4.8) + +### Fixed Bugs + +* fix: [ImageMagickHandler] early terminate processing of invalid library path by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8680 +* docs: fix PHPDoc types in BaseModel by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8679 +* fix: the error view is determined by Exception code by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8689 +* fix: `Pager::only([])` does not work by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8702 +* refactor: remove unneeded code in SQLite3\Table and fix PHPDoc types in Database by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8703 +* docs: fix return type in BaseResult by @Pebryan354 in https://github.com/codeigniter4/CodeIgniter4/pull/8709 + +### Refactoring + +* refactor: simplify ImageMagickHandler::getVersion() by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8681 +* refactor: [Rector] Apply ExplicitBoolCompareRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8704 + ## [v4.4.7](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.7) (2024-03-29) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.6...v4.4.7) +### SECURITY + +* **Language:** *Language class DoS Vulnerability* was fixed. See the + [Security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-39fp-mqmm-gxj6) + for more information. +* **URI Security:** The feature to check if URIs do not contain not permitted + strings has been added. This check is equivalent to the URI Security found in + CodeIgniter 3. This is enabled by default, but upgraded users need to add + a setting to enable it. +* **Filters:** A bug where URI paths processed by Filters were not URL-decoded + has been fixed. + ### Breaking Changes * fix: Time::difference() DST bug by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8661 diff --git a/admin/RELEASE.md b/admin/RELEASE.md index b168f7856354..37173c4e97b0 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -88,7 +88,7 @@ Work off direct clones of the repos so the release branches persist for a time. > generating much new content. * [ ] Replace **CHANGELOG.md** with the new version generated above -* [ ] Update **user_guide_src/source/changelogs/{version}.rst** +* [ ] Update **user_guide_src/source/changelogs/v4.x.x.rst** * Remove the section titles that have no items * [ ] Update **user_guide_src/source/installation/upgrade_{ver}.rst** * fill in the "All Changes" section, and add it to **upgrading.rst** @@ -150,10 +150,10 @@ Work off direct clones of the repos so the release branches persist for a time. composer test && composer info codeigniter4/framework ``` * [ ] Verify that the user guide actions succeeded: - * "[Deploy Distributable Repos](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/deploy-distributables.yml)", the main repo - * "[Deploy Production](https://github.com/codeigniter4/userguide/actions/workflows/deploy.yml)", UG repo - * "[pages-build-deployment](https://github.com/codeigniter4/userguide/actions/workflows/pages/pages-build-deployment)", UG repo - * Check if "CodeIgniter4.x.x.epub" is added to UG repo. "CodeIgniter.epub" was + * [ ] "[Deploy Distributable Repos](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/deploy-distributables.yml)", the main repo + * [ ] "[Deploy Production](https://github.com/codeigniter4/userguide/actions/workflows/deploy.yml)", UG repo + * [ ] "[pages-build-deployment](https://github.com/codeigniter4/userguide/actions/workflows/pages/pages-build-deployment)", UG repo + * [ ] Check if "CodeIgniter4.x.x.epub" is added to UG repo. "CodeIgniter.epub" was created when v4.3.8 was released. * [ ] Fast-forward `develop` branch to catch the merge commit from `master` ```console diff --git a/admin/prepare-release.php b/admin/prepare-release.php index 374e37b313eb..c0dcab6866ce 100644 --- a/admin/prepare-release.php +++ b/admin/prepare-release.php @@ -26,6 +26,7 @@ function replace_file_content(string $path, string $pattern, string $replace): v // Creates a branch for release. system('git switch develop'); +system('git branch -D release-' . $version); system('git switch -c release-' . $version); // Updates version number in "CodeIgniter.php". diff --git a/app/.htaccess b/app/.htaccess index f24db0accc73..3462048add78 100644 --- a/app/.htaccess +++ b/app/.htaccess @@ -1,6 +1,6 @@ - Require all denied + Require all denied - Deny from all + Deny from all diff --git a/composer.json b/composer.json index 4021508a3a87..b5baf427017a 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "1.0.3", + "rector/rector": "1.0.4", "vimeo/psalm": "^5.0" }, "replace": { diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml index ad7f3f7d8066..616f6aeae98d 100644 --- a/phpdoc.dist.xml +++ b/phpdoc.dist.xml @@ -10,7 +10,7 @@ api/build/ api/cache/ - + system diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 3380da0b8733..8dd1905e6b96 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -226,11 +226,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/BaseModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\BaseModel\\:\\:setValidationRules\\(\\) has parameter \\$validationRules with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\BaseModel\\:\\:transformDataToArray\\(\\) return type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -266,66 +261,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/BaseModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterDelete type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterFind type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterInsert type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterInsertBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterUpdate type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$afterUpdateBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeDelete type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeFind type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeInsert type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeInsertBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeUpdate type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\BaseModel\\:\\:\\$beforeUpdateBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/BaseModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Strict comparison using \\!\\=\\= between mixed and null will always evaluate to true\\.$#', 'count' => 1, @@ -451,16 +386,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/CLI/CLI.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, array given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/CLI/CLI.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/CLI/CLI.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in a ternary operator condition, string\\|null given\\.$#', 'count' => 1, @@ -771,11 +696,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Database/MigrateStatus.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, array\\, array\\\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/MigrateStatus.php', -]; $ignoreErrors[] = [ 'message' => '#^Parameter \\#1 \\$params \\(array\\\\) of method CodeIgniter\\\\Commands\\\\Database\\\\MigrateStatus\\:\\:run\\(\\) should be contravariant with parameter \\$params \\(array\\\\) of method CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:run\\(\\)$#', 'count' => 1, @@ -2136,11 +2056,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Config/DotEnv.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Config/DotEnv.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Config\\\\Factories\\:\\:__callStatic\\(\\) has parameter \\$arguments with no value type specified in iterable type array\\.$#', 'count' => 1, @@ -2291,11 +2206,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Controller.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, array given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Controller.php', -]; $ignoreErrors[] = [ 'message' => '#^Property CodeIgniter\\\\Controller\\:\\:\\$request \\(CodeIgniter\\\\HTTP\\\\CLIRequest\\|CodeIgniter\\\\HTTP\\\\IncomingRequest\\) does not accept CodeIgniter\\\\HTTP\\\\RequestInterface\\.$#', 'count' => 1, @@ -2856,16 +2766,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Database/BaseConnection.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_foreignKeyData\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Database/BaseConnection.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_indexData\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Database/BaseConnection.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:callFunction\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#', 'count' => 1, @@ -2901,11 +2801,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Database/BaseConnection.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:foreignKeyDataToObjects\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Database/BaseConnection.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:getFieldNames\\(\\) return type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -2916,11 +2811,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Database/BaseConnection.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:getIndexData\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Database/BaseConnection.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:listTables\\(\\) return type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -3736,11 +3626,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Database/OCI8/Builder.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Database/OCI8/Builder.php', -]; $ignoreErrors[] = [ 'message' => '#^PHPDoc type CodeIgniter\\\\Database\\\\OCI8\\\\Connection of property CodeIgniter\\\\Database\\\\OCI8\\\\Builder\\:\\:\\$db is not the same as PHPDoc type CodeIgniter\\\\Database\\\\BaseConnection of overridden property CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:\\$db\\.$#', 'count' => 1, @@ -6221,11 +6106,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/HTTP/DownloadResponse.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in an if condition, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/HTTP/DownloadResponse.php', -]; $ignoreErrors[] = [ 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\DownloadResponse\\) of method CodeIgniter\\\\HTTP\\\\DownloadResponse\\:\\:sendBody\\(\\) should be covariant with return type \\(\\$this\\(CodeIgniter\\\\HTTP\\\\Response\\)\\) of method CodeIgniter\\\\HTTP\\\\Response\\:\\:sendBody\\(\\)$#', 'count' => 1, @@ -7121,66 +7001,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 1024\\> given\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 128\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 16\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 1\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 2048\\> given\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 256\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 2\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 32\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 4\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 512\\> given\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 64\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, 8\\> given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/filesystem_helper.php', -]; $ignoreErrors[] = [ 'message' => '#^Right side of && is always true\\.$#', 'count' => 1, @@ -7391,11 +7211,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Helpers/form_helper.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/form_helper.php', -]; $ignoreErrors[] = [ 'message' => '#^Function _list\\(\\) has parameter \\$attributes with no value type specified in iterable type array\\.$#', 'count' => 1, @@ -7476,11 +7291,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Helpers/html_helper.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/html_helper.php', -]; $ignoreErrors[] = [ 'message' => '#^Function d\\(\\) has parameter \\$vars with no value type specified in iterable type array\\.$#', 'count' => 1, @@ -7581,11 +7391,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Helpers/url_helper.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/url_helper.php', -]; $ignoreErrors[] = [ 'message' => '#^Variable \\$atts might not be defined\\.$#', 'count' => 1, @@ -7723,7 +7528,7 @@ ]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 9, + 'count' => 8, 'path' => __DIR__ . '/system/Images/Handlers/ImageMagickHandler.php', ]; $ignoreErrors[] = [ @@ -8046,21 +7851,11 @@ 'count' => 1, 'path' => __DIR__ . '/system/Pager/Pager.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in an if condition, array given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Pager/Pager.php', -]; $ignoreErrors[] = [ 'message' => '#^Property CodeIgniter\\\\Pager\\\\Pager\\:\\:\\$groups type has no value type specified in iterable type array\\.$#', 'count' => 1, 'path' => __DIR__ . '/system/Pager/Pager.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\Pager\\\\Pager\\:\\:\\$only type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Pager/Pager.php', -]; $ignoreErrors[] = [ 'message' => '#^Property CodeIgniter\\\\Pager\\\\Pager\\:\\:\\$segment type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -8391,11 +8186,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Router/RouteCollection.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Router/RouteCollection.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in a ternary operator condition, string\\|null given\\.$#', 'count' => 1, @@ -8646,11 +8436,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Session/Handlers/FileHandler.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, string given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Session/Handlers/FileHandler.php', -]; $ignoreErrors[] = [ 'message' => '#^PHPDoc type string of property CodeIgniter\\\\Session\\\\Handlers\\\\FileHandler\\:\\:\\$savePath is not the same as PHPDoc type array\\|string of overridden property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$savePath\\.$#', 'count' => 1, @@ -9396,16 +9181,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Test/Mock/MockConnection.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Test\\\\Mock\\\\MockConnection\\:\\:_foreignKeyData\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Test/Mock/MockConnection.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\Test\\\\Mock\\\\MockConnection\\:\\:_indexData\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Test/Mock/MockConnection.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Test\\\\Mock\\\\MockConnection\\:\\:shouldReturn\\(\\) has no return type specified\\.$#', 'count' => 1, @@ -10611,11 +10386,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/View/Table.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, float given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/View/Table.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in an if condition, string\\|null given\\.$#', 'count' => 1, @@ -11286,71 +11056,11 @@ 'count' => 1, 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterDelete type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterFind type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterInsert type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterInsertBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterUpdate type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$afterUpdateBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeDelete type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeFind type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeFindReturnData has no type specified\\.$#', 'count' => 1, 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeInsert type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeInsertBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeUpdate type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$beforeUpdateBatch type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/EventModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Property Tests\\\\Support\\\\Models\\\\EventModel\\:\\:\\$eventData has no type specified\\.$#', 'count' => 1, @@ -11391,16 +11101,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/_support/Models/UserModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\ValidErrorsModel\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\|string\\>\\|string\\>\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/ValidErrorsModel.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Tests\\\\Support\\\\Models\\\\ValidModel\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\|string\\>\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/_support/Models/ValidModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Property Tests\\\\Support\\\\SomeEntity\\:\\:\\$attributes type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -12051,11 +11751,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/system/Cache/ResponseCacheTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, array given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Cache/ResponseCacheTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Re\\-assigning arrays to \\$_GET directly is discouraged\\.$#', 'count' => 3, @@ -16301,41 +15996,11 @@ 'count' => 1, 'path' => __DIR__ . '/tests/system/Models/UpdateModelTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelRuleGroupTest\\.php\\:368\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelRuleGroupTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelRuleGroupTest\\.php\\:406\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelRuleGroupTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelRuleGroupTest\\.php\\:446\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelRuleGroupTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelTest\\.php\\:243\\:\\:\\$grouptest has no type specified\\.$#', 'count' => 1, 'path' => __DIR__ . '/tests/system/Models/ValidationModelTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelTest\\.php\\:380\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelTest\\.php\\:418\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property class@anonymous/tests/system/Models/ValidationModelTest\\.php\\:458\\:\\:\\$validationRules \\(array\\\\|string\\) does not accept default value of type array\\\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/Models/ValidationModelTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Cannot access property \\$key on array\\.$#', 'count' => 7, diff --git a/public/.htaccess b/public/.htaccess index dbed322fdc1e..abac3cb6b949 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -45,5 +45,5 @@ Options -Indexes # Disable server signature start - ServerSignature Off +ServerSignature Off # Disable server signature end diff --git a/rector.php b/rector.php index 321bf3930b06..e52be465b4e5 100644 --- a/rector.php +++ b/rector.php @@ -21,6 +21,7 @@ use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector; use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\If_\CombineIfRector; +use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector; use Rector\CodeQuality\Rector\If_\ShortenElseIfRector; use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector; use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; @@ -158,6 +159,7 @@ $rectorConfig->rule(BooleanInIfConditionRuleFixerRector::class); $rectorConfig->rule(SingleInArrayToCompareRector::class); $rectorConfig->rule(VersionCompareFuncCallToConstantRector::class); + $rectorConfig->rule(ExplicitBoolCompareRector::class); $rectorConfig ->ruleWithConfiguration(StringClassNameToClassConstantRector::class, [ diff --git a/system/BaseModel.php b/system/BaseModel.php index 24479ec69362..cd2bdd6beb22 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -173,11 +173,14 @@ abstract class BaseModel protected $db; /** - * Rules used to validate data in insert, update, and save methods. + * Rules used to validate data in insert(), update(), and save() methods. + * * The array must match the format of data passed to the Validation * library. * - * @var list|string + * @see https://codeigniter4.github.io/userguide/models/model.html#setting-validation-rules + * + * @var array|string>|string>|string */ protected $validationRules = []; @@ -243,84 +246,84 @@ abstract class BaseModel /** * Callbacks for beforeInsert * - * @var array + * @var list */ protected $beforeInsert = []; /** * Callbacks for afterInsert * - * @var array + * @var list */ protected $afterInsert = []; /** * Callbacks for beforeUpdate * - * @var array + * @var list */ protected $beforeUpdate = []; /** * Callbacks for afterUpdate * - * @var array + * @var list */ protected $afterUpdate = []; /** * Callbacks for beforeInsertBatch * - * @var array + * @var list */ protected $beforeInsertBatch = []; /** * Callbacks for afterInsertBatch * - * @var array + * @var list */ protected $afterInsertBatch = []; /** * Callbacks for beforeUpdateBatch * - * @var array + * @var list */ protected $beforeUpdateBatch = []; /** * Callbacks for afterUpdateBatch * - * @var array + * @var list */ protected $afterUpdateBatch = []; /** * Callbacks for beforeFind * - * @var array + * @var list */ protected $beforeFind = []; /** * Callbacks for afterFind * - * @var array + * @var list */ protected $afterFind = []; /** * Callbacks for beforeDelete * - * @var array + * @var list */ protected $beforeDelete = []; /** * Callbacks for afterDelete * - * @var array + * @var list */ protected $afterDelete = []; @@ -1448,7 +1451,7 @@ public function setValidationMessage(string $field, array $fieldMessages) * Allows to set (and reset) validation rules. * It could be used when you have to change default or override current validate rules. * - * @param array $validationRules Value + * @param array|string>|string> $validationRules Value * * @return $this */ diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 9a50e4038184..5bd8543896ef 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -262,7 +262,7 @@ public static function prompt(string $field, $options = null, $validation = null $default = $options[0]; } - static::fwrite(STDOUT, $field . (trim($field) ? ' ' : '') . $extraOutput . ': '); + static::fwrite(STDOUT, $field . (trim($field) !== '' ? ' ' : '') . $extraOutput . ': '); // Read the input from keyboard. $input = trim(static::input()) ?: $default; @@ -386,7 +386,7 @@ public static function promptByMultipleKeys(string $text, array $options): array */ private static function isZeroOptions(array $options): void { - if (! $options) { + if ($options === []) { throw new InvalidArgumentException('No options to select from were provided'); } } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 760a71f29259..6a2dca68c1e5 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -54,7 +54,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.4.7'; + public const CI_VERSION = '4.4.8'; /** * App startup time. diff --git a/system/Commands/Database/MigrateStatus.php b/system/Commands/Database/MigrateStatus.php index cbbe2f70ce47..ecd074278d47 100644 --- a/system/Commands/Database/MigrateStatus.php +++ b/system/Commands/Database/MigrateStatus.php @@ -144,7 +144,7 @@ public function run(array $params) } } - if (! $status) { + if ($status === []) { // @codeCoverageIgnoreStart CLI::error(lang('Migrations.noneFound'), 'light_gray', 'red'); CLI::newLine(); diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index 05ecab900c3e..f8e757e9eab5 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -140,7 +140,7 @@ public function normaliseVariable(string $name, string $value = ''): array */ protected function sanitizeValue(string $value): string { - if (! $value) { + if ($value === '') { return $value; } diff --git a/system/Controller.php b/system/Controller.php index 0cc14c569651..83bc4f4b120e 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -187,7 +187,7 @@ private function setValidator($rules, array $messages): void } // If no error message is defined, use the error message in the Config\Validation file - if (! $messages) { + if ($messages === []) { $errorName = $rules . '_errors'; $messages = $validation->{$errorName} ?? []; } diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 8a33e220d84d..65dea86da2b3 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -333,7 +333,7 @@ public function __construct($tableName, ConnectionInterface $db, ?array $options /** * Returns the current database connection * - * @return BaseConnection|ConnectionInterface + * @return BaseConnection */ public function db(): ConnectionInterface { diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index ae5c4b3805f1..93bde5ddca6d 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1527,7 +1527,7 @@ public function getFieldData(string $table) /** * Returns an object with key data * - * @return array + * @return array */ public function getIndexData(string $table) { @@ -1547,7 +1547,9 @@ public function getForeignKeyData(string $table) /** * Converts array of arrays generated by _foreignKeyData() to array of objects * - * @return array[ + * @return array + * + * array[ * {constraint_name} => * stdClass[ * 'constraint_name' => string, @@ -1704,6 +1706,8 @@ abstract protected function _fieldData(string $table): array; * Platform-specific index data. * * @see getIndexData() + * + * @return array */ abstract protected function _indexData(string $table): array; @@ -1711,6 +1715,8 @@ abstract protected function _indexData(string $table): array; * Platform-specific foreign keys data. * * @see getForeignKeyData() + * + * @return array */ abstract protected function _foreignKeyData(string $table): array; diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index 8a624029b3a2..8720b5fe111c 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -260,8 +260,8 @@ public function getResultObject(): array * @param string $type The type of result object. 'array', 'object' or class name. * @phpstan-param class-string|'array'|'object' $type * - * @return array|object|stdClass|null - * @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : T|null)) + * @return array|float|int|object|stdClass|string|null + * @phpstan-return ($n is string ? float|int|string|null : ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : T|null))) */ public function getRow($n = 0, string $type = 'object') { diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 03aab408398a..b499e2ca81d6 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -443,7 +443,7 @@ protected function _fieldData(string $table): array /** * Returns an array of objects with index data * - * @return list + * @return array * * @throws DatabaseException * @throws LogicException @@ -489,7 +489,7 @@ protected function _indexData(string $table): array /** * Returns an array of objects with Foreign key data * - * @return list + * @return array * * @throws DatabaseException */ diff --git a/system/Database/OCI8/Builder.php b/system/Database/OCI8/Builder.php index f5527ce745c6..37ba54a27392 100644 --- a/system/Database/OCI8/Builder.php +++ b/system/Database/OCI8/Builder.php @@ -222,7 +222,7 @@ protected function _limit(string $sql, bool $offsetIgnore = false): string } $this->limitUsed = true; - $limitTemplateQuery = 'SELECT * FROM (SELECT INNER_QUERY.*, ROWNUM RNUM FROM (%s) INNER_QUERY WHERE ROWNUM < %d)' . ($offset ? ' WHERE RNUM >= %d' : ''); + $limitTemplateQuery = 'SELECT * FROM (SELECT INNER_QUERY.*, ROWNUM RNUM FROM (%s) INNER_QUERY WHERE ROWNUM < %d)' . ($offset !== 0 ? ' WHERE RNUM >= %d' : ''); return sprintf($limitTemplateQuery, $sql, $offset + $this->QBLimit + 1, $offset); } diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index fc7920e2a8ff..2feb2d36df4b 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -325,7 +325,7 @@ protected function _fieldData(string $table): array /** * Returns an array of objects with index data * - * @return list + * @return array * * @throws DatabaseException */ @@ -374,7 +374,7 @@ protected function _indexData(string $table): array /** * Returns an array of objects with Foreign key data * - * @return list + * @return array * * @throws DatabaseException */ diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index baef703b7bb3..7da3d26c9dd8 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -332,7 +332,7 @@ protected function _fieldData(string $table): array /** * Returns an array of objects with index data * - * @return list + * @return array * * @throws DatabaseException */ @@ -371,7 +371,7 @@ protected function _indexData(string $table): array /** * Returns an array of objects with Foreign key data * - * @return list + * @return array * * @throws DatabaseException */ diff --git a/system/Database/ResultInterface.php b/system/Database/ResultInterface.php index ea5f0de2800f..2b1deb98c6b6 100644 --- a/system/Database/ResultInterface.php +++ b/system/Database/ResultInterface.php @@ -63,8 +63,8 @@ public function getResultObject(): array; * @param string $type The type of result object. 'array', 'object' or class name. * @phpstan-param class-string|'array'|'object' $type * - * @return array|object|stdClass|null - * @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : T|null)) + * @return array|float|int|object|stdClass|string|null + * @phpstan-return ($n is string ? float|int|string|null : ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : T|null))) */ public function getRow($n = 0, string $type = 'object'); diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index bc3e036078c9..77a1ab34bcf3 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -231,7 +231,7 @@ protected function _listColumns(string $table = ''): string /** * Returns an array of objects with index data * - * @return list + * @return array * * @throws DatabaseException */ @@ -269,7 +269,7 @@ protected function _indexData(string $table): array * Returns an array of objects with Foreign key data * referenced_object_id parent_object_id * - * @return list + * @return array * * @throws DatabaseException */ diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index be4ebc25f0ca..a7ac179dadca 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -286,7 +286,7 @@ protected function _fieldData(string $table): array /** * Returns an array of objects with index data * - * @return list + * @return array * * @throws DatabaseException */ @@ -343,7 +343,7 @@ protected function _indexData(string $table): array /** * Returns an array of objects with Foreign key data * - * @return list + * @return array */ protected function _foreignKeyData(string $table): array { diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 47e6d1a7097e..bd2056d581d9 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -280,7 +280,7 @@ public function addForeignKey(array $foreignKeys) /** * Creates the new table based on our current fields. * - * @return mixed + * @return bool */ protected function createTable() { @@ -449,16 +449,12 @@ private function isNumericType(string $type): bool * Converts keys retrieved from the database to * the format needed to create later. * - * @param mixed $keys + * @param array $keys * - * @return mixed + * @return array */ protected function formatKeys($keys) { - if (! is_array($keys)) { - return $keys; - } - $return = []; foreach ($keys as $name => $key) { diff --git a/system/Debug/ExceptionHandler.php b/system/Debug/ExceptionHandler.php index 63449888ffb5..09c6de0d5b7e 100644 --- a/system/Debug/ExceptionHandler.php +++ b/system/Debug/ExceptionHandler.php @@ -97,8 +97,8 @@ public function handle( . DIRECTORY_SEPARATOR . 'errors' . DIRECTORY_SEPARATOR . $addPath; // Determine the views - $view = $this->determineView($exception, $path); - $altView = $this->determineView($exception, $altPath); + $view = $this->determineView($exception, $path, $statusCode); + $altView = $this->determineView($exception, $altPath, $statusCode); // Check if the view exists $viewFile = null; @@ -119,13 +119,16 @@ public function handle( } /** - * Determines the view to display based on the exception thrown, - * whether an HTTP or CLI request, etc. + * Determines the view to display based on the exception thrown, HTTP status + * code, whether an HTTP or CLI request, etc. * * @return string The filename of the view file to use */ - protected function determineView(Throwable $exception, string $templatePath): string - { + protected function determineView( + Throwable $exception, + string $templatePath, + int $statusCode = 500 + ): string { // Production environments should have a custom exception file. $view = 'production.php'; @@ -147,8 +150,8 @@ protected function determineView(Throwable $exception, string $templatePath): st $templatePath = rtrim($templatePath, '\\/ ') . DIRECTORY_SEPARATOR; // Allow for custom views based upon the status code - if (is_file($templatePath . 'error_' . $exception->getCode() . '.php')) { - return 'error_' . $exception->getCode() . '.php'; + if (is_file($templatePath . 'error_' . $statusCode . '.php')) { + return 'error_' . $statusCode . '.php'; } return $view; diff --git a/system/HTTP/DownloadResponse.php b/system/HTTP/DownloadResponse.php index 14dc3fec1421..d815a9af6e03 100644 --- a/system/HTTP/DownloadResponse.php +++ b/system/HTTP/DownloadResponse.php @@ -194,7 +194,7 @@ private function getContentDisposition(): string $result = sprintf('attachment; filename="%s"', $downloadFilename); - if ($utf8Filename) { + if ($utf8Filename !== '') { $result .= '; filename*=UTF-8\'\'' . rawurlencode($utf8Filename); } diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 70ece748d834..e0725e7c90d5 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -15,8 +15,6 @@ use CodeIgniter\HTTP\Exceptions\HTTPException; use Config\Mimes; use Exception; -use InvalidArgumentException; -use RuntimeException; /** * Value object representing a single file uploaded through an @@ -80,12 +78,12 @@ class UploadedFile extends File implements UploadedFileInterface /** * Accepts the file information as would be filled in from the $_FILES array. * - * @param string $path The temporary location of the uploaded file. - * @param string $originalName The client-provided filename. - * @param string $mimeType The type of file as provided by PHP - * @param int $size The size of the file, in bytes - * @param int $error The error constant of the upload (one of PHP's UPLOADERRXXX constants) - * @param string $clientPath The webkit relative path of the uploaded file. + * @param string $path The temporary location of the uploaded file. + * @param string $originalName The client-provided filename. + * @param string|null $mimeType The type of file as provided by PHP + * @param int|null $size The size of the file, in bytes + * @param int|null $error The error constant of the upload (one of PHP's UPLOADERRXXX constants) + * @param string|null $clientPath The webkit relative path of the uploaded file. */ public function __construct(string $path, string $originalName, ?string $mimeType = null, ?int $size = null, ?int $error = null, ?string $clientPath = null) { @@ -122,16 +120,12 @@ public function __construct(string $path, string $originalName, ?string $mimeTyp * @see http://php.net/is_uploaded_file * @see http://php.net/move_uploaded_file * - * @param string $targetPath Path to which to move the uploaded file. - * @param string $name the name to rename the file to. - * @param bool $overwrite State for indicating whether to overwrite the previously generated file with the same - * name or not. + * @param string $targetPath Path to which to move the uploaded file. + * @param string|null $name the name to rename the file to. + * @param bool $overwrite State for indicating whether to overwrite the previously generated file with the same + * name or not. * * @return bool - * - * @throws InvalidArgumentException if the $path specified is invalid. - * @throws RuntimeException on any error during the move operation. - * @throws RuntimeException on the second or subsequent call to the method. */ public function move(string $targetPath, ?string $name = null, bool $overwrite = false) { @@ -345,8 +339,8 @@ public function isValid(): bool * By default, upload files are saved in writable/uploads directory. The YYYYMMDD folder * and random file name will be created. * - * @param string $folderName the folder name to writable/uploads directory. - * @param string $fileName the name to rename the file to. + * @param string|null $folderName the folder name to writable/uploads directory. + * @param string|null $fileName the name to rename the file to. * * @return string file full path */ diff --git a/system/HTTP/Files/UploadedFileInterface.php b/system/HTTP/Files/UploadedFileInterface.php index 170f81c2de9e..ef2073f2b876 100644 --- a/system/HTTP/Files/UploadedFileInterface.php +++ b/system/HTTP/Files/UploadedFileInterface.php @@ -26,12 +26,12 @@ interface UploadedFileInterface /** * Accepts the file information as would be filled in from the $_FILES array. * - * @param string $path The temporary location of the uploaded file. - * @param string $originalName The client-provided filename. - * @param string $mimeType The type of file as provided by PHP - * @param int $size The size of the file, in bytes - * @param int $error The error constant of the upload (one of PHP's UPLOADERRXXX constants) - * @param string $clientPath The webkit relative path of the uploaded file. + * @param string $path The temporary location of the uploaded file. + * @param string $originalName The client-provided filename. + * @param string|null $mimeType The type of file as provided by PHP + * @param int|null $size The size of the file, in bytes + * @param int|null $error The error constant of the upload (one of PHP's UPLOADERRXXX constants) + * @param string|null $clientPath The webkit relative path of the uploaded file. */ public function __construct(string $path, string $originalName, ?string $mimeType = null, ?int $size = null, ?int $error = null, ?string $clientPath = null); @@ -57,13 +57,12 @@ public function __construct(string $path, string $originalName, ?string $mimeTyp * @see http://php.net/is_uploaded_file * @see http://php.net/move_uploaded_file * - * @param string $targetPath Path to which to move the uploaded file. - * @param string $name the name to rename the file to. + * @param string $targetPath Path to which to move the uploaded file. + * @param string|null $name the name to rename the file to. * * @return bool * * @throws InvalidArgumentException if the $path specified is invalid. - * @throws RuntimeException on any error during the move operation. * @throws RuntimeException on the second or subsequent call to the method. */ public function move(string $targetPath, ?string $name = null); diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 4e0e8b1532e9..46700ffc2797 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -379,19 +379,19 @@ function symbolic_permissions(int $perms): string } // Owner - $symbolic .= (($perms & 0x0100) ? 'r' : '-') - . (($perms & 0x0080) ? 'w' : '-') - . (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x') : (($perms & 0x0800) ? 'S' : '-')); + $symbolic .= ((($perms & 0x0100) !== 0) ? 'r' : '-') + . ((($perms & 0x0080) !== 0) ? 'w' : '-') + . ((($perms & 0x0040) !== 0) ? ((($perms & 0x0800) !== 0) ? 's' : 'x') : ((($perms & 0x0800) !== 0) ? 'S' : '-')); // Group - $symbolic .= (($perms & 0x0020) ? 'r' : '-') - . (($perms & 0x0010) ? 'w' : '-') - . (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x') : (($perms & 0x0400) ? 'S' : '-')); + $symbolic .= ((($perms & 0x0020) !== 0) ? 'r' : '-') + . ((($perms & 0x0010) !== 0) ? 'w' : '-') + . ((($perms & 0x0008) !== 0) ? ((($perms & 0x0400) !== 0) ? 's' : 'x') : ((($perms & 0x0400) !== 0) ? 'S' : '-')); // World - $symbolic .= (($perms & 0x0004) ? 'r' : '-') - . (($perms & 0x0002) ? 'w' : '-') - . (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x') : (($perms & 0x0200) ? 'T' : '-')); + $symbolic .= ((($perms & 0x0004) !== 0) ? 'r' : '-') + . ((($perms & 0x0002) !== 0) ? 'w' : '-') + . ((($perms & 0x0001) !== 0) ? ((($perms & 0x0200) !== 0) ? 't' : 'x') : ((($perms & 0x0200) !== 0) ? 'T' : '-')); return $symbolic; } diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index 098222e90e9f..5f62cca83d6d 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -29,7 +29,7 @@ function form_open(string $action = '', $attributes = [], array $hidden = []): string { // If no action is provided then set to the current url - if (! $action) { + if ($action === '') { $action = current_url(true); } // If an action is not a full URL then turn it into one elseif (strpos($action, '://') === false) { diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 0f7e154a02bf..6d9a51356af6 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -195,7 +195,7 @@ function doctype(string $type = 'html5'): string function script_tag($src = '', bool $indexPage = false): string { $cspNonce = csp_script_nonce(); - $cspNonce = $cspNonce ? ' ' . $cspNonce : $cspNonce; + $cspNonce = $cspNonce !== '' ? ' ' . $cspNonce : $cspNonce; $script = ' $src]; diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index f992eac391f8..988d7de88a2f 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -318,7 +318,7 @@ function safe_mailto(string $email, string $title = '', $attributes = ''): strin // improve obfuscation by eliminating newlines & whitespace $cspNonce = csp_script_nonce(); - $cspNonce = $cspNonce ? ' ' . $cspNonce : $cspNonce; + $cspNonce = $cspNonce !== '' ? ' ' . $cspNonce : $cspNonce; $output = '' . 'var l=new Array();'; diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index cb8ce9bae763..d5396958e3ed 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -32,8 +32,6 @@ class ImageMagickHandler extends BaseHandler protected $resource; /** - * Constructor. - * * @param Images $config * * @throws ImageException @@ -45,6 +43,22 @@ public function __construct($config = null) if (! (extension_loaded('imagick') || class_exists(Imagick::class))) { throw ImageException::forMissingExtension('IMAGICK'); // @codeCoverageIgnore } + + $cmd = $this->config->libraryPath; + + if ($cmd === '') { + throw ImageException::forInvalidImageLibraryPath($cmd); + } + + if (preg_match('/convert$/i', $cmd) !== 1) { + $cmd = rtrim($cmd, '\/') . '/convert'; + + $this->config->libraryPath = $cmd; + } + + if (! is_file($cmd)) { + throw ImageException::forInvalidImageLibraryPath($cmd); + } } /** @@ -167,12 +181,10 @@ protected function _flip(string $direction) */ public function getVersion(): string { - $result = $this->process('-version'); + $versionString = $this->process('-version')[0]; + preg_match('/ImageMagick\s(?P[\S]+)/', $versionString, $matches); - // The first line has the version in it... - preg_match('/(ImageMagick\s[\S]+)/', $result[0], $matches); - - return str_replace('ImageMagick ', '', $matches[0]); + return $matches['version']; } /** @@ -184,19 +196,10 @@ public function getVersion(): string */ protected function process(string $action, int $quality = 100): array { - // Do we have a vaild library path? - if (empty($this->config->libraryPath)) { - throw ImageException::forInvalidImageLibraryPath($this->config->libraryPath); - } - if ($action !== '-version') { $this->supportedFormatCheck(); } - if (! preg_match('/convert$/i', $this->config->libraryPath)) { - $this->config->libraryPath = rtrim($this->config->libraryPath, '/') . '/convert'; - } - $cmd = $this->config->libraryPath; $cmd .= $action === '-version' ? ' ' . $action : ' -quality ' . $quality . ' ' . $action; diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index d9de5faab401..0834fe09f0e4 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -60,9 +60,9 @@ class Pager implements PagerInterface /** * List of only permitted queries * - * @var array + * @var list|null */ - protected $only = []; + protected $only; /** * Constructor. @@ -276,7 +276,7 @@ public function getPageURI(?int $page = null, string $group = 'default', bool $r $uri->addQuery($this->groups[$group]['pageSelector'], $page); } - if ($this->only) { + if ($this->only !== null) { $query = array_intersect_key($_GET, array_flip($this->only)); if (! $segment) { diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 2adb0ed98638..117f3a218da6 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -767,7 +767,7 @@ public function group(string $name, ...$params) // To register a route, we'll set a flag so that our router // will see the group name. // If the group name is empty, we go on using the previously built group name. - $this->group = $name ? trim($oldGroup . '/' . $name, '/') : $oldGroup; + $this->group = $name !== '' ? trim($oldGroup . '/' . $name, '/') : $oldGroup; $callback = array_pop($params); diff --git a/system/Session/Handlers/FileHandler.php b/system/Session/Handlers/FileHandler.php index 9eb642408381..62513d399c4a 100644 --- a/system/Session/Handlers/FileHandler.php +++ b/system/Session/Handlers/FileHandler.php @@ -73,7 +73,7 @@ public function __construct(SessionConfig $config, string $ipAddress) } else { $sessionPath = rtrim(ini_get('session.save_path'), '/\\'); - if (! $sessionPath) { + if ($sessionPath === '') { $sessionPath = WRITEPATH . 'session'; } diff --git a/system/View/Table.php b/system/View/Table.php index c9cd33d39ac6..65b43195d988 100644 --- a/system/View/Table.php +++ b/system/View/Table.php @@ -365,7 +365,7 @@ public function generate($tableData = null) foreach ($this->rows as $row) { // We use modulus to alternate the row colors - $name = fmod($i++, 2) ? '' : 'alt_'; + $name = fmod($i++, 2) !== 0.0 ? '' : 'alt_'; $out .= $this->template['row_' . $name . 'start'] . $this->newline; diff --git a/tests/.htaccess b/tests/.htaccess index f24db0accc73..3462048add78 100644 --- a/tests/.htaccess +++ b/tests/.htaccess @@ -1,6 +1,6 @@ - Require all denied + Require all denied - Deny from all + Deny from all diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index b34cfce95c37..d55d625cd7e2 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -48,7 +48,7 @@ private function createIncomingRequest( ): IncomingRequest { $_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = []; - $_SERVER['REQUEST_URI'] = '/' . $uri . ($query ? '?' . http_build_query($query) : ''); + $_SERVER['REQUEST_URI'] = '/' . $uri . ($query !== [] ? '?' . http_build_query($query) : ''); $_SERVER['SCRIPT_NAME'] = '/index.php'; $appConfig ??= $this->appConfig; diff --git a/tests/system/Debug/ExceptionHandlerTest.php b/tests/system/Debug/ExceptionHandlerTest.php index 8dcad8e6c338..a55227ab7a34 100644 --- a/tests/system/Debug/ExceptionHandlerTest.php +++ b/tests/system/Debug/ExceptionHandlerTest.php @@ -69,7 +69,7 @@ public function testDetermineViewsRuntimeExceptionCode404(): void $templatePath = APPPATH . 'Views/errors/html'; $viewFile = $determineView($exception, $templatePath); - $this->assertSame('error_404.php', $viewFile); + $this->assertSame('error_exception.php', $viewFile); } public function testDetermineViewsDisplayErrorsOffRuntimeException(): void diff --git a/tests/system/Images/ImageMagickHandlerTest.php b/tests/system/Images/ImageMagickHandlerTest.php index b313fef96275..cb48b35ee7b3 100644 --- a/tests/system/Images/ImageMagickHandlerTest.php +++ b/tests/system/Images/ImageMagickHandlerTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Config\Services; use CodeIgniter\Images\Exceptions\ImageException; use CodeIgniter\Images\Handlers\BaseHandler; +use CodeIgniter\Images\Handlers\ImageMagickHandler; use CodeIgniter\Test\CIUnitTestCase; use Config\Images; use Imagick; @@ -77,14 +78,40 @@ protected function setUp(): void $this->handler = Services::image('imagick', $config, false); } + /** + * @dataProvider provideNonexistentLibraryPathTerminatesProcessing + */ + public function testNonexistentLibraryPathTerminatesProcessing(string $path, string $invalidPath): void + { + $this->expectException(ImageException::class); + $this->expectExceptionMessage(lang('Images.libPathInvalid', [$invalidPath])); + + $config = new Images(); + + $config->libraryPath = $path; + + new ImageMagickHandler($config); + } + + /** + * @return iterable> + */ + public static function provideNonexistentLibraryPathTerminatesProcessing(): iterable + { + yield 'empty string' => ['', '']; + + yield 'invalid file' => ['/var/log/convert', '/var/log/convert']; + + yield 'nonexistent file' => ['/var/www/file', '/var/www/file/convert']; + } + public function testGetVersion(): void { $version = $this->handler->getVersion(); - // make sure that the call worked - $this->assertNotFalse($version); - // we should have a numeric version, greater than 6 - $this->assertGreaterThanOrEqual(0, version_compare($version, '6.0.0')); - $this->assertLessThan(0, version_compare($version, '99.0.0')); + + $this->assertNotSame('', $version); + $this->assertTrue(version_compare($version, '6.0.0', '>')); + $this->assertTrue(version_compare($version, '99.0.0', '<')); } public function testImageProperties(): void diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index f5059f082b53..25c923265f33 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -165,6 +165,10 @@ public function testStoreWithQueries(): void 'http://example.com/?foo=bar&page=5', $this->pager->only(['foo'])->getPageURI(5) ); + $this->assertSame( + 'http://example.com/?page=5', + $this->pager->only([])->getPageURI(5) + ); } public function testStoreWithSegments(): void @@ -181,6 +185,10 @@ public function testStoreWithSegments(): void 'http://example.com/5?foo=bar', $this->pager->only(['foo'])->getPageURI(5) ); + $this->assertSame( + 'http://example.com/5', + $this->pager->only([])->getPageURI(5) + ); } public function testGetPageURIWithURIReturnObject(): void diff --git a/user_guide_src/.htaccess b/user_guide_src/.htaccess index f24db0accc73..3462048add78 100644 --- a/user_guide_src/.htaccess +++ b/user_guide_src/.htaccess @@ -1,6 +1,6 @@ - Require all denied + Require all denied - Deny from all + Deny from all diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index 6d5e51f49210..0f18260929b1 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,6 +12,7 @@ See all the changes. .. toctree:: :titlesonly: + v4.4.8 v4.4.7 v4.4.6 v4.4.5 diff --git a/user_guide_src/source/changelogs/v4.4.8.rst b/user_guide_src/source/changelogs/v4.4.8.rst new file mode 100644 index 000000000000..723f129175ec --- /dev/null +++ b/user_guide_src/source/changelogs/v4.4.8.rst @@ -0,0 +1,28 @@ +############# +Version 4.4.8 +############# + +Release Date: April 7, 2024 + +**4.4.8 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 3 + +******** +BREAKING +******** + +- A bug that caused the :doc:`Exception handler <../general/errors>` to display + incorrect error view file corresponding to the exception code has been fixed. + The third parameter ``int $statusCode = 500`` has been added to + ``CodeIgniter\Debug\ExceptionHandler::determineView()`` for this purpose. + +********** +Bugs Fixed +********** + +See the repo's +`CHANGELOG.md `_ +for a complete list of bugs fixed. diff --git a/user_guide_src/source/concepts/security.rst b/user_guide_src/source/concepts/security.rst index df1bd2b34827..6d8f5839e8f3 100644 --- a/user_guide_src/source/concepts/security.rst +++ b/user_guide_src/source/concepts/security.rst @@ -10,224 +10,924 @@ We respect the `Open Web Application Security Project (OWASP) `_, -identifying the top vulnerabilities for web applications. +`OWASP Top Ten `_ and +`OWASP API Security Top 10 `_ +identifying the top vulnerabilities for web applications and apis. For each, we provide a brief description, the OWASP recommendations, and then the CodeIgniter provisions to address the problem. .. contents:: :local: - :depth: 1 + :depth: 2 + +***************** +OWASP Top 10 2021 +***************** + +A01:2021 Broken Access Control +============================== + +Access control enforces policy such that users cannot act outside of their intended +permissions. Failures typically lead to unauthorized information disclosure, +modification, or destruction of all data or performing a business function outside +the user's limits. + +Common access control vulnerabilities include: + +- Violation of the principle of least privilege or deny by default, where access + should only be granted for particular capabilities, roles, or users, but is + available to anyone. +- Bypassing access control checks by modifying the URL (parameter tampering or + force browsing), internal application state, or the HTML page, or by using an + attack tool modifying API requests. +- Permitting viewing or editing someone else's account, by providing its unique + identifier (insecure direct object references) +- Accessing API with missing access controls for POST, PUT and DELETE. +- Elevation of privilege. Acting as a user without being logged in or acting as + an admin when logged in as a user. +- Metadata manipulation, such as replaying or tampering with a JSON Web Token (JWT) + access control token, or a cookie or hidden field manipulated to elevate + privileges or abusing JWT invalidation. +- CORS misconfiguration allows API access from unauthorized/untrusted origins. +- Force browsing to authenticated pages as an unauthenticated user or to privileged + pages as a standard user. -************ -A1 Injection -************ +OWASP recommendations +--------------------- + +Access control is only effective in trusted server-side code or server-less API, +where the attacker cannot modify the access control check or metadata. + +- Except for public resources, deny by default. +- Implement access control mechanisms once and re-use them throughout the application, + including minimizing Cross-Origin Resource Sharing (CORS) usage. +- Model access controls should enforce record ownership rather than accepting that + the user can create, read, update, or delete any record. +- Unique application business limit requirements should be enforced by domain models. +- Disable web server directory listing and ensure file metadata (e.g., .git) and + backup files are not present within web roots. +- Log access control failures, alert admins when appropriate (e.g., repeated failures). +- Rate limit API and controller access to minimize the harm from automated attack + tooling. +- Stateful session identifiers should be invalidated on the server after logout. + Stateless JWT tokens should rather be short-lived so that the window of opportunity + for an attacker is minimized. For longer lived JWTs it's highly recommended to + follow the OAuth standards to revoke access. + +CodeIgniter provisions +---------------------- + +- :ref:`Public ` folder, with application and system + outside +- :doc:`../libraries/validation` library +- :doc:`Security ` library provides for + :ref:`CSRF protection ` +- :doc:`../libraries/throttler` for rate limit +- :php:func:`log_message()` function for logging +- An official authentication and authorization framework :ref:`CodeIgniter Shield ` +- Easy to add third party authentication -An injection is the inappropriate insertion of partial or complete data via -the input data from the client to the application. Attack vectors include SQL, -XML, ORM, code & buffer overflows. +A02:2021 Cryptographic Failures +=============================== + +The first thing is to determine the protection needs of data in transit and at +rest. For example, passwords, credit card numbers, health records, personal +information, and business secrets require extra protection, mainly if that data +falls under privacy laws, e.g., EU's General Data Protection Regulation (GDPR), +or regulations, e.g., financial data protection such as PCI Data Security Standard +(PCI DSS). For all such data: + +- Is any data transmitted in clear text? This concerns protocols such as HTTP, + SMTP, FTP also using TLS upgrades like STARTTLS. External internet traffic is + hazardous. Verify all internal traffic, e.g., between load balancers, web servers, + or back-end systems. +- Are any old or weak cryptographic algorithms or protocols used either by default + or in older code? +- Are default crypto keys in use, weak crypto keys generated or re-used, or is + proper key management or rotation missing? Are crypto keys checked into source + code repositories? +- Is encryption not enforced, e.g., are any HTTP headers (browser) security + directives or headers missing? +- Is the received server certificate and the trust chain properly validated? +- Are initialization vectors ignored, reused, or not generated sufficiently secure + for the cryptographic mode of operation? Is an insecure mode of operation such + as ECB in use? Is encryption used when authenticated encryption is more appropriate? +- Are passwords being used as cryptographic keys in absence of a password base key + derivation function? +- Is randomness used for cryptographic purposes that was not designed to meet + cryptographic requirements? Even if the correct function is chosen, does it need + to be seeded by the developer, and if not, has the developer over-written the + strong seeding functionality built into it with a seed that lacks sufficient + entropy/unpredictability? +- Are deprecated hash functions such as MD5 or SHA1 in use, or are non-cryptographic + hash functions used when cryptographic hash functions are needed? +- Are deprecated cryptographic padding methods such as PKCS number 1 v1.5 in use? +- Are cryptographic error messages or side channel information exploitable, for + example in the form of padding oracle attacks? OWASP recommendations -===================== +--------------------- + +Do the following, at a minimum, and consult the references: + +- Classify data processed, stored, or transmitted by an application. Identify which + data is sensitive according to privacy laws, regulatory requirements, or business + needs. +- Don't store sensitive data unnecessarily. Discard it as soon as possible or use + PCI DSS compliant tokenization or even truncation. Data that is not retained + cannot be stolen. +- Make sure to encrypt all sensitive data at rest. +- Ensure up-to-date and strong standard algorithms, protocols, and keys are in + place; use proper key management. +- Encrypt all data in transit with secure protocols such as TLS with forward secrecy + (FS) ciphers, cipher prioritization by the server, and secure parameters. Enforce + encryption using directives like HTTP Strict Transport Security (HSTS). +- Disable caching for response that contain sensitive data. +- Apply required security controls as per the data classification. +- Do not use legacy protocols such as FTP and SMTP for transporting sensitive data. +- Store passwords using strong adaptive and salted hashing functions with a work + factor (delay factor), such as Argon2, scrypt, bcrypt or PBKDF2. +- Initialization vectors must be chosen appropriate for the mode of operation. + For many modes, this means using a CSPRNG (cryptographically secure pseudo random + number generator). For modes that require a nonce, then the initialization vector + (IV) does not need a CSPRNG. In all cases, the IV should never be used twice for + a fixed key. +- Always use authenticated encryption instead of just encryption. +- Keys should be generated cryptographically randomly and stored in memory as byte + arrays. If a password is used, then it must be converted to a key via an + appropriate password base key derivation function. +- Ensure that cryptographic randomness is used where appropriate, and that it has + not been seeded in a predictable way or with low entropy. Most modern APIs do + not require the developer to seed the CSPRNG to get security. +- Avoid deprecated cryptographic functions and padding schemes, such as MD5, SHA1, + PKCS number 1 v1.5 . +- Verify independently the effectiveness of configuration and settings. -- Presentation: set correct content type, character set & locale -- Submission: validate fields and provide feedback -- Controller: sanitize input; positive input validation using correct character set -- Model: parameterized queries +CodeIgniter provisions +---------------------- + +- The config for global secure access (``Config\App::$forceGlobalSecureRequests``) +- :php:func:`force_https()` function +- :doc:`../libraries/encryption` +- The :ref:`database config ` (``encrypt``) +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` + +A03:2021 Injection +================== + +An application is vulnerable to attack when: + +- User-supplied data is not validated, filtered, or sanitized by the application. +- Dynamic queries or non-parameterized calls without context-aware escaping are + used directly in the interpreter. +- Hostile data is used within object-relational mapping (ORM) search parameters + to extract additional, sensitive records. +- Hostile data is directly used or concatenated. The SQL or command contains the + structure and malicious data in dynamic queries, commands, or stored procedures. + +Some of the more common injections are SQL, NoSQL, OS command, Object Relational +Mapping (ORM), LDAP, and Expression Language (EL) or Object Graph Navigation Library +(OGNL) injection. The concept is identical among all interpreters. Source code +review is the best method of detecting if applications are vulnerable to injections. +Automated testing of all parameters, headers, URL, cookies, JSON, SOAP, and XML +data inputs is strongly encouraged. Organizations can include static (SAST), +dynamic (DAST), and interactive (IAST) application security testing tools into +the CI/CD pipeline to identify introduced injection flaws before production deployment. + +OWASP recommendations +--------------------- + +Preventing injection requires keeping data separate from commands and queries: + +- The preferred option is to use a safe API, which avoids using the interpreter + entirely, provides a parameterized interface, or migrates to Object Relational + Mapping Tools (ORMs). + + - Note: Even when parameterized, stored procedures can still introduce SQL + injection if PL/SQL or T-SQL concatenates queries and data or executes hostile + data with EXECUTE IMMEDIATE or exec(). +- Use positive server-side input validation. This is not a complete defense as + many applications require special characters, such as text areas or APIs for + mobile applications. +- For any residual dynamic queries, escape special characters using the specific + escape syntax for that interpreter. + + - Note: SQL structures such as table names, column names, and so on cannot be + escaped, and thus user-supplied structure names are dangerous. This is a + common issue in report-writing software. +- Use LIMIT and other SQL controls within queries to prevent mass disclosure of + records in case of SQL injection. CodeIgniter provisions -====================== +---------------------- - :ref:`urls-uri-security` - :ref:`invalidchars` filter - :doc:`../libraries/validation` library -- :doc:`HTTP library <../incoming/incomingrequest>` provides for :ref:`input field filtering ` & content metadata +- :php:func:`esc()` function +- :doc:`HTTP library <../incoming/incomingrequest>` provides for + :ref:`input field filtering ` +- Support for :ref:`content-security-policy` +- :doc:`../database/query_builder` +- :ref:`Database escape methods ` +- :ref:`database-queries-query-bindings` + +A04:2021 Insecure Design +======================== + +Insecure design is a broad category representing different weaknesses, expressed +as “missing or ineffective control design.” Insecure design is not the source for +all other Top 10 risk categories. There is a difference between insecure design +and insecure implementation. We differentiate between design flaws and implementation +defects for a reason, they have different root causes and remediation. + +A secure design can still have implementation defects leading to vulnerabilities +that may be exploited. An insecure design cannot be fixed by a perfect implementation +as by definition, needed security controls were never created to defend against +specific attacks. One of the factors that contribute to insecure design is the +lack of business risk profiling inherent in the software or system being developed, +and thus the failure to determine what level of security design is required. + +OWASP recommendations +--------------------- + +- Establish and use a secure development lifecycle with AppSec professionals to + help evaluate and design security and privacy-related controls +- Establish and use a library of secure design patterns or paved road ready to + use components +- Use threat modeling for critical authentication, access control, business logic, + and key flows +- Integrate security language and controls into user stories +- Integrate plausibility checks at each tier of your application (from frontend + to backend) +- Write unit and integration tests to validate that all critical flows are resistant + to the threat model. Compile use-cases and misuse-cases for each tier of your + application. +- Segregate tier layers on the system and network layers depending on the exposure + and protection needs +- Segregate tenants robustly by design throughout all tiers +- Limit resource consumption by user or service + +CodeIgniter provisions +---------------------- -********************************************* -A2 Weak authentication and session management -********************************************* +- :doc:`PHPUnit testing <../testing/overview>` +- :doc:`../libraries/throttler` for rate limit +- An official authentication and authorization framework :ref:`CodeIgniter Shield ` -Inadequate authentication or improper session management can lead to a user -getting more privileges than they are entitled to. +A05:2021 Security Misconfiguration +================================== + +The application might be vulnerable if the application is: + +- Missing appropriate security hardening across any part of the application stack + or improperly configured permissions on cloud services. +- Unnecessary features are enabled or installed (e.g., unnecessary ports, services, + pages, accounts, or privileges). +- Default accounts and their passwords are still enabled and unchanged. +- Error handling reveals stack traces or other overly informative error messages + to users. +- For upgraded systems, the latest security features are disabled or not configured + securely. +- The security settings in the application servers, application frameworks (e.g., + Struts, Spring, ASP.NET), libraries, databases, etc., are not set to secure values. +- The server does not send security headers or directives, or they are not set to + secure values. +- The software is out of date or vulnerable (see A06:2021-Vulnerable and Outdated + Components). + +Without a concerted, repeatable application security configuration process, +systems are at a higher risk. OWASP recommendations -===================== +--------------------- + +Secure installation processes should be implemented, including: + +- A repeatable hardening process makes it fast and easy to deploy another environment + that is appropriately locked down. Development, QA, and production environments + should all be configured identically, with different credentials used in each + environment. This process should be automated to minimize the effort required + to set up a new secure environment. +- A minimal platform without any unnecessary features, components, documentation, + and samples. Remove or do not install unused features and frameworks. +- A task to review and update the configurations appropriate to all security notes, + updates, and patches as part of the patch management process (see A06:2021-Vulnerable + and Outdated Components). Review cloud storage permissions (e.g., S3 bucket permissions). +- A segmented application architecture provides effective and secure separation + between components or tenants, with segmentation, containerization, or cloud + security groups (ACLs). +- Sending security directives to clients, e.g., Security Headers. +- An automated process to verify the effectiveness of the configurations and + settings in all environments. + +CodeIgniter provisions +---------------------- + +- :ref:`Production mode ` by default +- :ref:`secureheaders` filter + +A06:2021 Vulnerable and Outdated Components +=========================================== + +You are likely vulnerable: + +- If you do not know the versions of all components you use (both client-side + and server-side). This includes components you directly use as well as nested + dependencies. +- If the software is vulnerable, unsupported, or out of date. This includes the OS, + web/application server, database management system (DBMS), applications, APIs + and all components, runtime environments, and libraries. +- If you do not scan for vulnerabilities regularly and subscribe to security + bulletins related to the components you use. +- If you do not fix or upgrade the underlying platform, frameworks, and dependencies + in a risk-based, timely fashion. This commonly happens in environments when + patching is a monthly or quarterly task under change control, leaving organizations + open to days or months of unnecessary exposure to fixed vulnerabilities. +- If software developers do not test the compatibility of updated, upgraded, or + patched libraries. +- If you do not secure the components’ configurations (see A05:2021-Security + Misconfiguration). -- Presentation: validate authentication & role; send CSRF token with forms -- Design: only use built-in session management -- Controller: validate user, role, CSRF token -- Model: validate role -- Tip: consider the use of a request governor +OWASP recommendations +--------------------- + +There should be a patch management process in place to: + +- Remove unused dependencies, unnecessary features, components, files, and + documentation. +- Continuously inventory the versions of both client-side and server-side components + (e.g., frameworks, libraries) and their dependencies using tools like versions, + OWASP Dependency Check, retire.js, etc. Continuously monitor sources like Common + Vulnerability and Exposures (CVE) and National Vulnerability Database (NVD) for + vulnerabilities in the components. Use software composition analysis tools to + automate the process. Subscribe to email alerts for security vulnerabilities + related to components you use. +- Only obtain components from official sources over secure links. Prefer signed + packages to reduce the chance of including a modified, malicious component + (See A08:2021-Software and Data Integrity Failures). +- Monitor for libraries and components that are unmaintained or do not create + security patches for older versions. If patching is not possible, consider + deploying a virtual patch to monitor, detect, or protect against the discovered + issue. + +Every organization must ensure an ongoing plan for monitoring, triaging, and +applying updates or configuration changes for the lifetime of the application or +portfolio. CodeIgniter provisions -====================== +---------------------- + +- Easy :ref:`app-starter-upgrading` by Composer + +A07:2021 Identification and Authentication Failures +=================================================== + +Confirmation of the user's identity, authentication, and session management is +critical to protect against authentication-related attacks. There may be +authentication weaknesses if the application: + +- Permits automated attacks such as credential stuffing, where the attacker has + a list of valid usernames and passwords. +- Permits brute force or other automated attacks. +- Permits default, weak, or well-known passwords, such as "Password1" or "admin/admin". +- Uses weak or ineffective credential recovery and forgot-password processes, + such as "knowledge-based answers," which cannot be made safe. +- Uses plain text, encrypted, or weakly hashed passwords data stores + (see A02:2021-Cryptographic Failures). +- Has missing or ineffective multi-factor authentication. +- Exposes session identifier in the URL. +- Reuse session identifier after successful login. +- Does not correctly invalidate Session IDs. User sessions or authentication tokens + (mainly single sign-on (SSO) tokens) aren't properly invalidated during logout + or a period of inactivity. + +OWASP recommendations +--------------------- + +- Where possible, implement multi-factor authentication to prevent automated + credential stuffing, brute force, and stolen credential reuse attacks. +- Do not ship or deploy with any default credentials, particularly for admin users. +- Implement weak password checks, such as testing new or changed passwords against + the top 10,000 worst passwords list. +- Align password length, complexity, and rotation policies with National Institute + of Standards and Technology (NIST) 800-63b's guidelines in section 5.1.1 for + Memorized Secrets or other modern, evidence-based password policies. +- Ensure registration, credential recovery, and API pathways are hardened against + account enumeration attacks by using the same messages for all outcomes. +- Limit or increasingly delay failed login attempts, but be careful not to create + a denial of service scenario. Log all failures and alert administrators when + credential stuffing, brute force, or other attacks are detected. +- Use a server-side, secure, built-in session manager that generates a new random + session ID with high entropy after login. Session identifier should not be in + the URL, be securely stored, and invalidated after logout, idle, and absolute + timeouts. + +CodeIgniter provisions +---------------------- - :doc:`Session <../libraries/sessions>` library -- :doc:`Security ` library provides for CSRF validation -- An official authentication and authorization framework :ref:`CodeIgniter Shield ` -- Easy to add third party authentication +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` -***************************** -A3 Cross Site Scripting (XSS) -***************************** +A08:2021 Software and Data Integrity Failures +============================================= -Insufficient input validation where one user can add content to a web site -that can be malicious when viewed by other users to the web site. +Software and data integrity failures relate to code and infrastructure that does +not protect against integrity violations. An example of this is where an application +relies upon plugins, libraries, or modules from untrusted sources, repositories, +and content delivery networks (CDNs). An insecure CI/CD pipeline can introduce +the potential for unauthorized access, malicious code, or system compromise. + +Lastly, many applications now include auto-update functionality, where updates +are downloaded without sufficient integrity verification and applied to the previously +trusted application. Attackers could potentially upload their own updates to be +distributed and run on all installations. + +Another example is where objects or data are encoded or serialized into a structure +that an attacker can see and modify is vulnerable to insecure deserialization. OWASP recommendations -===================== +--------------------- + +- Use digital signatures or similar mechanisms to verify the software or data is + from the expected source and has not been altered. +- Ensure libraries and dependencies, such as npm or Maven, are consuming trusted + repositories. If you have a higher risk profile, consider hosting an internal + known-good repository that's vetted. +- Ensure that a software supply chain security tool, such as OWASP Dependency + Check or OWASP CycloneDX, is used to verify that components do not contain + known vulnerabilities +- Ensure that there is a review process for code and configuration changes to + minimize the chance that malicious code or configuration could be introduced + into your software pipeline. +- Ensure that your CI/CD pipeline has proper segregation, configuration, and + access control to ensure the integrity of the code flowing through the build + and deploy processes. +- Ensure that unsigned or unencrypted serialized data is not sent to untrusted + clients without some form of integrity check or digital signature to detect + tampering or replay of the serialized data -- Presentation: output encode all user data as per output context; set input constraints -- Controller: positive input validation -- Tips: only process trustworthy data; do not store data HTML encoded in DB +CodeIgniter provisions +---------------------- + +- n/a + +A09:2021 Security Logging and Monitoring Failures +================================================= + +This category is to help detect, escalate, and respond to active breaches. Without +logging and monitoring, breaches cannot be detected. Insufficient logging, detection, +monitoring, and active response occurs any time: + +- Auditable events, such as logins, failed logins, and high-value transactions, + are not logged. +- Warnings and errors generate no, inadequate, or unclear log messages. +- Logs of applications and APIs are not monitored for suspicious activity. +- Logs are only stored locally. +- Appropriate alerting thresholds and response escalation processes are not in + place or effective. +- Penetration testing and scans by dynamic application security testing (DAST) + tools (such as OWASP ZAP) do not trigger alerts. +- The application cannot detect, escalate, or alert for active attacks in real-time + or near real-time. + +You are vulnerable to information leakage by making logging and alerting events +visible to a user or an attacker (see A01:2021-Broken Access Control). + +OWASP recommendations +--------------------- + +Developers should implement some or all the following controls, depending on the risk of the application: + +- Ensure all login, access control, and server-side input validation failures can + be logged with sufficient user context to identify suspicious or malicious + accounts and held for enough time to allow delayed forensic analysis. +- Ensure that logs are generated in a format that log management solutions can + easily consume. +- Ensure log data is encoded correctly to prevent injections or attacks on the + logging or monitoring systems. +- Ensure high-value transactions have an audit trail with integrity controls to + prevent tampering or deletion, such as append-only database tables or similar. +- DevSecOps teams should establish effective monitoring and alerting such that + suspicious activities are detected and responded to quickly. +- Establish or adopt an incident response and recovery plan, such as National + Institute of Standards and Technology (NIST) 800-61r2 or later. + +There are commercial and open-source application protection frameworks such as +the OWASP ModSecurity Core Rule Set, and open-source log correlation software, +such as the Elasticsearch, Logstash, Kibana (ELK) stack, that feature custom +dashboards and alerting. CodeIgniter provisions -====================== +---------------------- -- :php:func:`esc()` function -- :doc:`../libraries/validation` library -- Support for :ref:`content-security-policy` +- :doc:`Logging <../general/logging>` library +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` + +A10:2021 Server-Side Request Forgery (SSRF) +=========================================== -*********************************** -A4 Insecure Direct Object Reference -*********************************** +SSRF flaws occur whenever a web application is fetching a remote resource without +validating the user-supplied URL. It allows an attacker to coerce the application +to send a crafted request to an unexpected destination, even when protected by a +firewall, VPN, or another type of network access control list (ACL). -Insecure Direct Object References occur when an application provides direct -access to objects based on user-supplied input. As a result of this vulnerability -attackers can bypass authorization and access resources in the system directly, -for example database records or files. +As modern web applications provide end-users with convenient features, fetching +a URL becomes a common scenario. As a result, the incidence of SSRF is increasing. +Also, the severity of SSRF is becoming higher due to cloud services and the +complexity of architectures. OWASP recommendations -===================== +--------------------- + +Developers can prevent SSRF by implementing some or all the following defense in +depth controls: -- Presentation: don't expose internal data; use random reference maps -- Controller: obtain data from trusted sources or random reference maps -- Model: validate user roles before updating data +From Network layer: + +- Segment remote resource access functionality in separate networks to reduce the + impact of SSRF +- Enforce “deny by default” firewall policies or network access control rules to + block all but essential intranet traffic. + + - Hints: + + * Establish an ownership and a lifecycle for firewall rules based on + applications. + * Log all accepted and blocked network flows on firewalls + (see A09:2021-Security Logging and Monitoring Failures). + +From Application layer: + +- Sanitize and validate all client-supplied input data +- Enforce the URL schema, port, and destination with a positive allow list +- Do not send raw responses to clients +- Disable HTTP redirections +- Be aware of the URL consistency to avoid attacks such as DNS rebinding and + “time of check, time of use” (TOCTOU) race conditions + +Do not mitigate SSRF via the use of a deny list or regular expression. Attackers +have payload lists, tools, and skills to bypass deny lists. CodeIgniter provisions -====================== +---------------------- - :doc:`../libraries/validation` library -- An official authentication and authorization framework :ref:`CodeIgniter Shield ` -- Easy to add third party authentication +- :doc:`HTTP library <../incoming/incomingrequest>` provides for + :ref:`input field filtering ` + +****************************** +OWASP API Security Top 10 2023 +****************************** -**************************** -A5 Security Misconfiguration -**************************** +API1:2023 Broken Object Level Authorization +=========================================== -Improper configuration of an application architecture can lead to mistakes -that might compromise the security of the whole architecture. +APIs tend to expose endpoints that handle object identifiers, creating a wide +attack surface of Object Level Access Control issues. Object level authorization +checks should be considered in every function that accesses a data source using +an ID from the user. OWASP recommendations -===================== +--------------------- -- Presentation: harden web and application servers; use HTTP strict transport security -- Controller: harden web and application servers; protect your XML stack -- Model: harden database servers +- Implement a proper authorization mechanism that relies on the user policies and + hierarchy. +- Use the authorization mechanism to check if the logged-in user has access to + perform the requested action on the record in every function that uses an input + from the client to access a record in the database. +- Prefer the use of random and unpredictable values as GUIDs for records' IDs. +- Write tests to evaluate the vulnerability of the authorization mechanism. Do + not deploy changes that make the tests fail. CodeIgniter provisions -====================== +---------------------- -- Sanity checks during bootstrap +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` -************************** -A6 Sensitive Data Exposure -************************** +API2:2023 Broken Authentication +=============================== -Sensitive data must be protected when it is transmitted through the network. -Such data can include user credentials and credit cards. As a rule of thumb, -if data must be protected when it is stored, it must be protected also during -transmission. +Authentication mechanisms are often implemented incorrectly, allowing attackers +to compromise authentication tokens or to exploit implementation flaws to assume +other user's identities temporarily or permanently. Compromising a system's +ability to identify the client/user, compromises API security overall. OWASP recommendations -===================== +--------------------- + +- Make sure you know all the possible flows to authenticate to the API (mobile/ + web/deep links that implement one-click authentication/etc.). Ask your engineers + what flows you missed. +- Read about your authentication mechanisms. Make sure you understand what and + how they are used. OAuth is not authentication, and neither are API keys. +- Don't reinvent the wheel in authentication, token generation, or password storage. + Use the standards. +- Credential recovery/forgot password endpoints should be treated as login + endpoints in terms of brute force, rate limiting, and lockout protections. +- Require re-authentication for sensitive operations (e.g. changing the account + owner email address/2FA phone number). +- Use the OWASP Authentication Cheatsheet. +- Where possible, implement multi-factor authentication. +- Implement anti-brute force mechanisms to mitigate credential stuffing, dictionary + attacks, and brute force attacks on your authentication endpoints. This mechanism + should be stricter than the regular rate limiting mechanisms on your APIs. +- Implement account lockout/captcha mechanisms to prevent brute force attacks + against specific users. Implement weak-password checks. +- API keys should not be used for user authentication. They should only be used + for API clients authentication. + +CodeIgniter provisions +---------------------- + +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` + +API3:2023 Broken Object Property Level Authorization +==================================================== -- Presentation: use TLS1.2; use strong ciphers and hashes; do not send keys or hashes to browser -- Controller: use strong ciphers and hashes -- Model: mandate strong encrypted communications with servers +This category combines API3:2019 Excessive Data Exposure and API6:2019 - Mass +Assignment, focusing on the root cause: the lack of or improper authorization +validation at the object property level. This leads to information exposure or +manipulation by unauthorized parties. + +OWASP recommendations +--------------------- + +- When exposing an object using an API endpoint, always make sure that the user + should have access to the object's properties you expose. +- Avoid using generic methods such as to_json() and to_string(). Instead, + cherry-pick specific object properties you specifically want to return. +- If possible, avoid using functions that automatically bind a client's input + into code variables, internal objects, or object properties ("Mass Assignment"). +- Allow changes only to the object's properties that should be updated by the + client. +- Implement a schema-based response validation mechanism as an extra layer of + security. As part of this mechanism, define and enforce data returned by all + API methods. +- Keep returned data structures to the bare minimum, according to the + business/functional requirements for the endpoint. CodeIgniter provisions -====================== +---------------------- -- The config for global secure access (``Config\App::$forceGlobalSecureRequests``) -- :php:func:`force_https()` function -- :doc:`../libraries/encryption` -- The :ref:`database config ` (``encrypt``) +- Model's :ref:`model-allowed-fields` +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` -**************************************** -A7 Missing Function Level Access Control -**************************************** +API4:2023 Unrestricted Resource Consumption +=========================================== -Sensitive data must be protected when it is transmitted through the network. -Such data can include user credentials and credit cards. As a rule of thumb, -if data must be protected when it is stored, it must be protected also during -transmission. +Satisfying API requests requires resources such as network bandwidth, CPU, memory, +and storage. Other resources such as emails/SMS/phone calls or biometrics validation +are made available by service providers via API integrations, and paid for per +request. Successful attacks can lead to Denial of Service or an increase of +operational costs. OWASP recommendations -===================== +--------------------- + +- Use a solution that makes it easy to limit memory, CPU, number of restarts, + file descriptors, and processes such as Containers / Serverless code (e.g. Lambdas). +- Define and enforce a maximum size of data on all incoming parameters and payloads, + such as maximum length for strings, maximum number of elements in arrays, and + maximum upload file size (regardless of whether it is stored locally or in + cloud storage). +- Implement a limit on how often a client can interact with the API within a + defined timeframe (rate limiting). +- Rate limiting should be fine tuned based on the business needs. Some API Endpoints + might require stricter policies. +- Limit/throttle how many times or how often a single API client/user can execute + a single operation (e.g. validate an OTP, or request password recovery without + visiting the one-time URL). +- Add proper server-side validation for query string and request body parameters, + specifically the one that controls the number of records to be returned in the + response. +- Configure spending limits for all service providers/API integrations. When setting + spending limits is not possible, billing alerts should be configured instead. -- Presentation: ensure that non-web data is outside the web root; validate users and roles; send CSRF tokens -- Controller: validate users and roles; validate CSRF tokens -- Model: validate roles +CodeIgniter provisions +---------------------- + +- :doc:`../libraries/validation` library +- :doc:`../libraries/throttler` for rate limit + +API5:2023 Broken Function Level Authorization +============================================= + +Complex access control policies with different hierarchies, groups, and roles, +and an unclear separation between administrative and regular functions, tend to +lead to authorization flaws. By exploiting these issues, attackers can gain +access to other users’ resources and/or administrative functions. + +OWASP recommendations +--------------------- + +Your application should have a consistent and easy-to-analyze authorization module +that is invoked from all your business functions. Frequently, such protection is +provided by one or more components external to the application code. + +- The enforcement mechanism(s) should deny all access by default, requiring explicit + grants to specific roles for access to every function. +- Review your API endpoints against function level authorization flaws, while + keeping in mind the business logic of the application and groups hierarchy. +- Make sure that all of your administrative controllers inherit from an + administrative abstract controller that implements authorization checks based + on the user's group/role. +- Make sure that administrative functions inside a regular controller implement + authorization checks based on the user's group and role. + +CodeIgniter provisions +---------------------- + +- An official authentication and authorization framework + :ref:`CodeIgniter Shield ` + +API6:2023 Unrestricted Access to Sensitive Business Flows +========================================================= + +APIs vulnerable to this risk expose a business flow - such as buying a ticket, +or posting a comment - without compensating for how the functionality could harm +the business if used excessively in an automated manner. This doesn't necessarily +come from implementation bugs. + +OWASP recommendations +--------------------- + +The mitigation planning should be done in two layers: + +- Business - identify the business flows that might harm the business if they + are excessively used. +- Engineering - choose the right protection mechanisms to mitigate the business + risk. + +Some of the protection mechanisms are more simple while others are more difficult +to implement. The following methods are used to slow down automated threats: + +- Device fingerprinting: denying service to unexpected client devices (e.g + headless browsers) tends to make threat actors use more sophisticated solutions, + thus more costly for them +- Human detection: using either captcha or more advanced biometric solutions + (e.g. typing patterns) +- Non-human patterns: analyze the user flow to detect non-human patterns + (e.g. the user accessed the "add to cart" and "complete purchase" functions in + less than one second) +- Consider blocking IP addresses of Tor exit nodes and well-known proxies + +Secure and limit access to APIs that are consumed directly by machines (such as +developer and B2B APIs). They tend to be an easy target for attackers because +they often don't implement all the required protection mechanisms. CodeIgniter provisions -====================== +---------------------- -- :ref:`Public ` folder, with application and system outside -- :doc:`Security ` library provides for :ref:`CSRF validation ` +- n/a -************************************ -A8 Cross Site Request Forgery (CSRF) -************************************ +API7:2023 Server Side Request Forgery +===================================== -CSRF is an attack that forces an end user to execute unwanted actions on a web -application in which he/she is currently authenticated. +Server-Side Request Forgery (SSRF) flaws can occur when an API is fetching a +remote resource without validating the user-supplied URI. This enables an attacker +to coerce the application to send a crafted request to an unexpected destination, +even when protected by a firewall or a VPN. OWASP recommendations -===================== +--------------------- + +- Isolate the resource fetching mechanism in your network: usually these features + are aimed to retrieve remote resources and not internal ones. +- Whenever possible, use allow lists of: -- Presentation: validate users and roles; send CSRF tokens -- Controller: validate users and roles; validate CSRF tokens -- Model: validate roles + - Remote origins users are expected to download resources from (e.g. Google Drive, + Gravatar, etc.) + - URL schemes and ports + - Accepted media types for a given functionality +- Disable HTTP redirections. +- Use a well-tested and maintained URL parser to avoid issues caused by URL parsing inconsistencies. +- Validate and sanitize all client-supplied input data. +- Do not send raw responses to clients. CodeIgniter provisions -====================== +---------------------- -- :doc:`Security ` library provides for :ref:`CSRF validation ` +- :doc:`../libraries/validation` library +- :doc:`HTTP library <../incoming/incomingrequest>` provides for + :ref:`input field filtering ` +- :doc:`CURLRequest <../libraries/curlrequest>` class +- :doc:`URI <../libraries/uri>` class -********************************************** -A9 Using Components with Known Vulnerabilities -********************************************** +API8:2023 Security Misconfiguration +=================================== -Many applications have known vulnerabilities and known attack strategies that -can be exploited in order to gain remote control or to exploit data. +APIs and the systems supporting them typically contain complex configurations, +meant to make the APIs more customizable. Software and DevOps engineers can miss +these configurations, or don't follow security best practices when it comes to +configuration, opening the door for different types of attacks. OWASP recommendations -===================== +--------------------- + +The API life cycle should include: + +- A repeatable hardening process leading to fast and easy deployment of a properly + locked down environment +- A task to review and update configurations across the entire API stack. The + review should include: orchestration files, API components, and cloud services + (e.g. S3 bucket permissions) +- An automated process to continuously assess the effectiveness of the configuration + and settings in all environments + +Furthermore: + +- Ensure that all API communications from the client to the API server and any + downstream/upstream components happen over an encrypted communication channel + (TLS), regardless of whether it is an internal or public-facing API. +- Be specific about which HTTP verbs each API can be accessed by: all other HTTP + verbs should be disabled (e.g. HEAD). +- APIs expecting to be accessed from browser-based clients (e.g., WebApp front-end) + should, at least: + + - implement a proper Cross-Origin Resource Sharing (CORS) policy + - include applicable Security Headers +- Restrict incoming content types/data formats to those that meet the business/ + functional requirements. +- Ensure all servers in the HTTP server chain (e.g. load balancers, reverse and + forward proxies, and back-end servers) process incoming requests in a uniform + manner to avoid desync issues. +- Where applicable, define and enforce all API response payload schemas, including + error responses, to prevent exception traces and other valuable information from + being sent back to attackers. + +CodeIgniter provisions +---------------------- + +- The config for global secure access (``Config\App::$forceGlobalSecureRequests``) +- :php:func:`force_https()` function +- :ref:`Defined Route Routing ` +- :ref:`auto-routing-improved` + +API9:2023 Improper Inventory Management +======================================= -- Don't use any of these +APIs tend to expose more endpoints than traditional web applications, making +proper and updated documentation highly important. A proper inventory of hosts +and deployed API versions also are important to mitigate issues such as deprecated +API versions and exposed debug endpoints. + +OWASP recommendations +--------------------- + +- Inventory all API hosts and document important aspects of each one of them, + focusing on the API environment (e.g. production, staging, test, development), + who should have network access to the host (e.g. public, internal, partners) + and the API version. +- Inventory integrated services and document important aspects such as their + role in the system, what data is exchanged (data flow), and their sensitivity. +- Document all aspects of your API such as authentication, errors, redirects, + rate limiting, cross-origin resource sharing (CORS) policy, and endpoints, + including their parameters, requests, and responses. +- Generate documentation automatically by adopting open standards. Include the + documentation build in your CI/CD pipeline. +- Make API documentation available only to those authorized to use the API. +- Use external protection measures such as API security specific solutions for + all exposed versions of your APIs, not just for the current production version. +- Avoid using production data with non-production API deployments. If this is + unavoidable, these endpoints should get the same security treatment as the + production ones. +- When newer versions of APIs include security improvements, perform a risk + analysis to inform the mitigation actions required for the older versions. For + example, whether it is possible to backport the improvements without breaking + API compatibility or if you need to take the older version out quickly and + force all clients to move to the latest version. CodeIgniter provisions -====================== +---------------------- -- Third party libraries incorporated must be vetted +- :ref:`routing-spark-routes` command -************************************** -A10 Unvalidated Redirects and Forwards -************************************** +API10:2023 Unsafe Consumption of APIs +===================================== -Faulty business logic or injected actionable code could redirect the user -inappropriately. +Developers tend to trust data received from third-party APIs more than user input, +and so tend to adopt weaker security standards. In order to compromise APIs, +attackers go after integrated third-party services instead of trying to compromise +the target API directly. OWASP recommendations -===================== +--------------------- -- Presentation: don't use URL redirection; use random indirect references -- Controller: don't use URL redirection; use random indirect references -- Model: validate roles +- When evaluating service providers, assess their API security posture. +- Ensure all API interactions happen over a secure communication channel (TLS). +- Always validate and properly sanitize data received from integrated APIs before + using it. +- Maintain an allowlist of well-known locations integrated APIs may redirect yours + to: do not blindly follow redirects. CodeIgniter provisions -====================== +---------------------- -- :doc:`HTTP library <../incoming/incomingrequest>` provides for ... -- :doc:`Session <../libraries/sessions>` library provides :ref:`sessions-flashdata` +- :doc:`../libraries/validation` library diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index d5735e310a47..bf80b5abef81 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -26,7 +26,7 @@ version = '4.4' # The full version, including alpha/beta/rc tags. -release = '4.4.7' +release = '4.4.8' # -- General configuration --------------------------------------------------- diff --git a/user_guide_src/source/database/metadata.rst b/user_guide_src/source/database/metadata.rst index 9ae08e5aae8d..85dcdc0b1d33 100644 --- a/user_guide_src/source/database/metadata.rst +++ b/user_guide_src/source/database/metadata.rst @@ -51,14 +51,14 @@ $db->getFieldNames() Returns an array containing the field names. This query can be called two ways: -1. You can supply the table name and call it from the ``$db->object``: +1. You can supply the table name and call it from the ``$db`` object: - .. literalinclude:: metadata/003.php + .. literalinclude:: metadata/003.php 2. You can gather the field names associated with any query you run by -calling the function from your query result object: + calling the function from your query result object: -.. literalinclude:: metadata/004.php + .. literalinclude:: metadata/004.php Determine If a Field is Present in a Table ========================================== diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst index b3904418b8a6..b0c7e6ded6a3 100644 --- a/user_guide_src/source/database/queries.rst +++ b/user_guide_src/source/database/queries.rst @@ -116,6 +116,7 @@ prefixing set ``true`` (boolean) via the second parameter: .. literalinclude:: queries/008.php +.. _database-queries-escaping: *************** Escaping Values @@ -160,6 +161,8 @@ strings are to be used in LIKE conditions so that LIKE wildcards yourself, it cannot automatically add the ``ESCAPE '!'`` condition for you, and so you'll have to manually do that. +.. _database-queries-query-bindings: + ************** Query Bindings ************** diff --git a/user_guide_src/source/database/transactions.rst b/user_guide_src/source/database/transactions.rst index bb58040ac4ce..4fe44c8929e5 100644 --- a/user_guide_src/source/database/transactions.rst +++ b/user_guide_src/source/database/transactions.rst @@ -67,11 +67,11 @@ Strict Mode can be disabled as follows: Managing Errors =============== -When you have ``DBDebug`` true in your **app/Config/Database.php** file, -if a query error occurs, all the queries will be rolled backed, and an exception -will be thrown. So you'll see a standard error page. +.. note:: + Since v4.3.0, during transactions, exceptions are not thrown by default + even if ``DBDebug`` is true. -If the ``DBDebug`` is false, you can manage your own errors like this: +You can manage your own errors like this: .. literalinclude:: transactions/003.php diff --git a/user_guide_src/source/general/errors.rst b/user_guide_src/source/general/errors.rst index 9e49711e7954..2b6eafce8c33 100644 --- a/user_guide_src/source/general/errors.rst +++ b/user_guide_src/source/general/errors.rst @@ -19,11 +19,17 @@ Using Exceptions This section is a quick overview for newer programmers, or for developers who are not experienced with using exceptions. +What is Exceptions +------------------ + Exceptions are simply events that happen when the exception is "thrown". This halts the current flow of the script, and execution is then sent to the error handler which displays the appropriate error page: .. literalinclude:: errors/001.php +Catching Exceptions +------------------- + If you are calling a method that might throw an exception, you can catch that exception using a ``try/catch`` block: .. literalinclude:: errors/002.php @@ -31,8 +37,11 @@ If you are calling a method that might throw an exception, you can catch that ex If the ``$userModel`` throws an exception, it is caught and the code within the catch block is executed. In this example, the scripts dies, echoing the error message that the ``UserModel`` defined. +Catching Specific Exceptions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + In the example above, we catch any type of Exception. If we only want to watch for specific types of exceptions, like -a ``UnknownFileException``, we can specify that in the catch parameter. Any other exceptions that are thrown and are +a ``DataException``, we can specify that in the catch parameter. Any other exceptions that are thrown and are not child classes of the caught exception will be passed on to the error handler: .. literalinclude:: errors/003.php @@ -65,7 +74,7 @@ See :ref:`setting-environment`. Logging Exceptions ------------------ -By default, all Exceptions other than 404 - Page Not Found exceptions are logged. This can be turned on and off +By default, all Exceptions other than "404 - Page Not Found" exceptions are logged. This can be turned on and off by setting the ``$log`` value of **app/Config/Exceptions.php**: .. literalinclude:: errors/005.php @@ -74,8 +83,40 @@ To ignore logging on other status codes, you can set the status code to ignore i .. literalinclude:: errors/006.php -.. note:: It is possible that logging still will not happen for exceptions if your current Log settings - are not set up to log **critical** errors, which all exceptions are logged as. +.. note:: It is possible that logging still will not happen for exceptions if your current + :ref:`Log settings ` + are not set up to log ``critical`` errors, which all exceptions are logged as. + +.. _logging_deprecation_warnings: + +Logging Deprecation Warnings +---------------------------- + +.. versionadded:: 4.3.0 + +By default, all errors reported by ``error_reporting()`` will be thrown as an ``ErrorException`` object. These +include both ``E_DEPRECATED`` and ``E_USER_DEPRECATED`` errors. With the surge in use of PHP 8.1+, many users +may see exceptions thrown for `passing null to non-nullable arguments of internal functions `_. +To ease the migration to PHP 8.1, you can instruct CodeIgniter to log the deprecations instead of throwing them. + +First, make sure your copy of ``Config\Exceptions`` is updated with the two new properties and set as follows: + +.. literalinclude:: errors/012.php + +Next, depending on the log level you set in ``Config\Exceptions::$deprecationLogLevel``, check whether the +logger threshold defined in ``Config\Logger::$threshold`` covers the deprecation log level. If not, adjust +it accordingly. + +.. literalinclude:: errors/013.php + +After that, subsequent deprecations will be logged instead of thrown. + +This feature also works with user deprecations: + +.. literalinclude:: errors/014.php + +For testing your application you may want to always throw on deprecations. You may configure this by +setting the environment variable ``CODEIGNITER_SCREAM_DEPRECATIONS`` to a truthy value. Framework Exceptions ==================== @@ -85,15 +126,17 @@ The following framework exceptions are available: PageNotFoundException --------------------- -This is used to signal a 404, Page Not Found error. When thrown, the system will show the view found at -**app/Views/errors/html/error_404.php**. You should customize all of the error views for your site. -If, in **app/Config/Routes.php**, you have specified a 404 Override, that will be called instead of the standard -404 page: +This is used to signal a 404, Page Not Found error: .. literalinclude:: errors/007.php You can pass a message into the exception that will be displayed in place of the default message on the 404 page. +For the default 404 view file location, see :ref:`http-status-code-and-error-views`. + +If, in **app/Config/Routing.php** or **app/Config/Routes.php**, you have specified +a :ref:`404-override`, that will be called instead of the standard 404 page. + ConfigException --------------- @@ -144,52 +187,52 @@ Specify HTTP Status Code in Your Exception .. versionadded:: 4.3.0 Since v4.3.0, you can specify the HTTP status code for your Exception class to implement -``HTTPExceptionInterface``. +``CodeIgniter\Exceptions\HTTPExceptionInterface``. When an exception implementing ``HTTPExceptionInterface`` is caught by CodeIgniter's exception handler, the Exception code will become the HTTP status code. -.. _error-specify-exit-code: +.. _http-status-code-and-error-views: -Specify Exit Code in Your Exception -=================================== +HTTP Status Code and Error Views +================================ -.. versionadded:: 4.3.0 +The exception handler displays the error view corresponding to the HTTP status +code, if one exists. -Since v4.3.0, you can specify the exit code for your Exception class to implement -``HasExitCodeInterface``. - -When an exception implementing ``HasExitCodeInterface`` is caught by CodeIgniter's exception handler, the code returned from the ``getExitCode()`` method will become the exit code. +For example, ``PageNotFoundException`` implements the ``HTTPExceptionInterface``, +so its exception code ``404`` will be the HTTP status code. Therefore if it is +thrown, the system will show the **error_404.php** in the **app/Views/errors/html** +folder when it is a web request. If it is invoked via CLI, the system will show +the **error_404.php** in the **app/Views/errors/cli** folder. -.. _logging_deprecation_warnings: +If there is no view file corresponding to the HTTP status code, **production.php** +or **error_exception.php** will be displayed. -Logging Deprecation Warnings -============================ - -.. versionadded:: 4.3.0 - -By default, all errors reported by ``error_reporting()`` will be thrown as an ``ErrorException`` object. These -include both ``E_DEPRECATED`` and ``E_USER_DEPRECATED`` errors. With the surge in use of PHP 8.1+, many users -may see exceptions thrown for `passing null to non-nullable arguments of internal functions `_. -To ease the migration to PHP 8.1, you can instruct CodeIgniter to log the deprecations instead of throwing them. +.. note:: If ``display_errors`` is on in the PHP INI configuration, + **error_exception.php** is selected and a detailed error report is displayed. -First, make sure your copy of ``Config\Exceptions`` is updated with the two new properties and set as follows: +You should customize all of the error views in the **app/Views/errors/html** folder +for your site. -.. literalinclude:: errors/012.php +You can also create error views for specific HTTP status code. For example, if +you want to create an error view for "400 Bad Request", add **error_400.php**. -Next, depending on the log level you set in ``Config\Exceptions::$deprecationLogLevel``, check whether the -logger threshold defined in ``Config\Logger::$threshold`` covers the deprecation log level. If not, adjust -it accordingly. +.. warning:: If an error view file with the corresponding HTTP status code exists, + the exception handler will display that file regardless of the environment. + The view file must be implemented in such a way that it does not display + detailed error messages in production environment by yourself. -.. literalinclude:: errors/013.php +.. _error-specify-exit-code: -After that, subsequent deprecations will be logged instead of thrown. +Specify Exit Code in Your Exception +=================================== -This feature also works with user deprecations: +.. versionadded:: 4.3.0 -.. literalinclude:: errors/014.php +Since v4.3.0, you can specify the exit code for your Exception class to implement +``CodeIgniter\Exceptions\HasExitCodeInterface``. -For testing your application you may want to always throw on deprecations. You may configure this by -setting the environment variable ``CODEIGNITER_SCREAM_DEPRECATIONS`` to a truthy value. +When an exception implementing ``HasExitCodeInterface`` is caught by CodeIgniter's exception handler, the code returned from the ``getExitCode()`` method will become the exit code. .. _custom-exception-handlers: diff --git a/user_guide_src/source/general/errors/003.php b/user_guide_src/source/general/errors/003.php index 2d230d34f29a..07418eef5504 100644 --- a/user_guide_src/source/general/errors/003.php +++ b/user_guide_src/source/general/errors/003.php @@ -1,7 +1,9 @@ find($id); -} catch (\CodeIgniter\UnknownFileException $e) { +} catch (DataException $e) { // do something here... } diff --git a/user_guide_src/source/general/errors/004.php b/user_guide_src/source/general/errors/004.php index 752b23bdba30..4b816ece1894 100644 --- a/user_guide_src/source/general/errors/004.php +++ b/user_guide_src/source/general/errors/004.php @@ -1,8 +1,10 @@ find($id); -} catch (\CodeIgniter\UnknownFileException $e) { +} catch (DataException $e) { // do something here... throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); diff --git a/user_guide_src/source/general/errors/005.php b/user_guide_src/source/general/errors/005.php index 54a3276fb46f..152a08137e7b 100644 --- a/user_guide_src/source/general/errors/005.php +++ b/user_guide_src/source/general/errors/005.php @@ -6,5 +6,7 @@ class Exceptions extends BaseConfig { - public $log = true; + // ... + public bool $log = true; + // ... } diff --git a/user_guide_src/source/general/errors/006.php b/user_guide_src/source/general/errors/006.php index 9d9bb636b2ff..614d61e18231 100644 --- a/user_guide_src/source/general/errors/006.php +++ b/user_guide_src/source/general/errors/006.php @@ -6,5 +6,7 @@ class Exceptions extends BaseConfig { - public $ignoredCodes = [404]; + // ... + public array $ignoreCodes = [404]; + // ... } diff --git a/user_guide_src/source/general/errors/007.php b/user_guide_src/source/general/errors/007.php index a06e5000737a..585f4aa6b68a 100644 --- a/user_guide_src/source/general/errors/007.php +++ b/user_guide_src/source/general/errors/007.php @@ -1,5 +1,9 @@ find($id)) { - throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); +use CodeIgniter\Exceptions\PageNotFoundException; + +$page = $pageModel->find($id); + +if ($page === null) { + throw PageNotFoundException::forPageNotFound(); } diff --git a/user_guide_src/source/images/error.png b/user_guide_src/source/images/error.png index 4c72bc4e43ff..14fac852d48f 100644 Binary files a/user_guide_src/source/images/error.png and b/user_guide_src/source/images/error.png differ diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index b1aa0e65a9a5..6c5984615fb6 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -185,7 +185,7 @@ Auto Routing (Improved) Since v4.2.0, the new more secure Auto Routing has been introduced. .. note:: If you are familiar with Auto Routing, which was enabled by default - from CodeIgniter 3 through 4.1.x, you can see the differences in + from CodeIgniter 3.x through 4.1.x, you can see the differences in :ref:`ChangeLog v4.2.0 `. This section describes the functionality of the new auto-routing. diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a9aa28602822..8557b8f7fa2c 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -664,6 +664,8 @@ to only those defined by you, by setting the ``$autoRoute`` property to false: .. warning:: If you use the :doc:`CSRF protection `, it does not protect **GET** requests. If the URI is accessible by the GET method, the CSRF protection will not work. +.. _404-override: + 404 Override ============ @@ -703,7 +705,7 @@ Auto Routing (Improved) Since v4.2.0, the new more secure Auto Routing has been introduced. .. note:: If you are familiar with Auto Routing, which was enabled by default - from CodeIgniter 3 through 4.1.x, you can see the differences in + from CodeIgniter 3.x through 4.1.x, you can see the differences in :ref:`ChangeLog v4.2.0 `. When no defined route is found that matches the URI, the system will attempt to match that URI against the controllers and methods when Auto Routing is enabled. diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst index 8b71ea2833b0..0eab10b25b76 100644 --- a/user_guide_src/source/installation/index.rst +++ b/user_guide_src/source/installation/index.rst @@ -7,7 +7,7 @@ or using `Composer `_. Which is right for you? - We recommend the Composer installation because it keeps CodeIgniter up to date easily. -- If you would like the simple "download & go" install that CodeIgniter3 +- If you would like the simple "download & go" install that CodeIgniter 3 is known for, choose the manual installation. However you choose to install and run CodeIgniter4, the latest diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index 69f89cfbdbd0..4bd823911b75 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -295,6 +295,30 @@ And edit **.htaccess** as follows: Satisfy All +And remove the redirect settings in **public/.htaccess**: + +.. code-block:: diff + + --- a/public/.htaccess + +++ b/public/.htaccess + @@ -16,16 +16,6 @@ Options -Indexes + # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase + # RewriteBase / + + - # Redirect Trailing Slashes... + - RewriteCond %{REQUEST_FILENAME} !-d + - RewriteCond %{REQUEST_URI} (.+)/$ + - RewriteRule ^ %1 [L,R=301] + - + - # Rewrite "www.example.com -> example.com" + - RewriteCond %{HTTPS} !=on + - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] + - + # Checks to see if the user is attempting to access a valid file, + # such as an image or css document, if this isn't true it sends the + # request to the front controller, index.php + Hosting with mod_userdir (Shared Hosts) ======================================= @@ -505,6 +529,31 @@ And edit **.htaccess** as follows: Satisfy All + +And remove the redirect settings in **public/.htaccess**: + +.. code-block:: diff + + --- a/public/.htaccess + +++ b/public/.htaccess + @@ -16,16 +16,6 @@ Options -Indexes + # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase + # RewriteBase / + + - # Redirect Trailing Slashes... + - RewriteCond %{REQUEST_FILENAME} !-d + - RewriteCond %{REQUEST_URI} (.+)/$ + - RewriteRule ^ %1 [L,R=301] + - + - # Rewrite "www.example.com -> example.com" + - RewriteCond %{HTTPS} !=on + - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] + - + # Checks to see if the user is attempting to access a valid file, + # such as an image or css document, if this isn't true it sends the + # request to the front controller, index.php + ********************* Bootstrapping the App ********************* diff --git a/user_guide_src/source/installation/upgrade_447.rst b/user_guide_src/source/installation/upgrade_447.rst index 562118bbbb78..d31496d601d3 100644 --- a/user_guide_src/source/installation/upgrade_447.rst +++ b/user_guide_src/source/installation/upgrade_447.rst @@ -118,6 +118,7 @@ All Changes This is a list of all files in the **project space** that received changes; many will be simple comments or formatting that have no effect on the runtime: +- app/Config/App.php - app/Config/Cache.php - app/Config/ContentSecurityPolicy.php - app/Config/Database.php diff --git a/user_guide_src/source/installation/upgrade_448.rst b/user_guide_src/source/installation/upgrade_448.rst new file mode 100644 index 000000000000..5dd3da148a03 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_448.rst @@ -0,0 +1,34 @@ +############################# +Upgrading from 4.4.7 to 4.4.8 +############################# + +Please refer to the upgrade instructions corresponding to your installation method. + +- :ref:`Composer Installation App Starter Upgrading ` +- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` +- :ref:`Manual Installation Upgrading ` + +.. contents:: + :local: + :depth: 2 + +************* +Project Files +************* + +Some files in the **project space** (root, app, public, writable) received updates. Due to +these files being outside of the **system** scope they will not be changed without your intervention. + +There are some third-party CodeIgniter modules available to assist with merging changes to +the project space: `Explore on Packagist `_. + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +- app/.htaccess +- composer.json +- public/.htaccess +- tests/.htaccess diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 1253e783bb2f..45205c4ec2d8 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -149,8 +149,8 @@ Helpers - `String Helper `_ functions in CI3 are included in :doc:`../helpers/text_helper` in CI4. - In CI4, ``redirect()`` is completely changed from CI3's. - - `redirect() Documentation CodeIgniter 3.X `_ - - `redirect() Documentation CodeIgniter 4.X <../general/common_functions.html#redirect>`_ + - `redirect() Documentation CodeIgniter 3.x `_ + - `redirect() Documentation CodeIgniter 4.x <../general/common_functions.html#redirect>`_ - In CI4, :php:func:`redirect()` returns a ``RedirectResponse`` instance instead of redirecting and terminating script execution. You must return it from Controllers or Controller Filters. @@ -240,6 +240,7 @@ Upgrading Libraries upgrade_encryption upgrade_file_upload upgrade_html_tables + upgrade_images upgrade_localization upgrade_migrations upgrade_pagination diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 6150b9a01ff6..04aa67c17ba4 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -8,8 +8,8 @@ Upgrade Configuration Documentations ============== -- `Config Documentation CodeIgniter 3.X `_ -- :doc:`Configuration Documentation CodeIgniter 4.X ` +- `Config Documentation CodeIgniter 3.x `_ +- :doc:`Configuration Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index 1a2dc9a9b4ce..20e93d376aa4 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -8,8 +8,8 @@ Upgrade Controllers Documentations ============== -- `Controller Documentation CodeIgniter 3.X `_ -- :doc:`Controller Documentation CodeIgniter 4.X ` +- `Controller Documentation CodeIgniter 3.x `_ +- :doc:`Controller Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 5dc22ddda820..b596ca01d775 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -8,8 +8,8 @@ Upgrade Database Documentations ============== -- `Database Reference Documentation CodeIgniter 3.X `_ -- :doc:`Working with Databases Documentation CodeIgniter 4.X ` +- `Database Reference Documentation CodeIgniter 3.x `_ +- :doc:`Working with Databases Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index 828cc83ce5f7..546debff6add 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -8,8 +8,8 @@ Upgrade Emails Documentations ============== -- `Email Documentation CodeIgniter 3.X `_ -- :doc:`Email Documentation CodeIgniter 4.X ` +- `Email Documentation CodeIgniter 3.x `_ +- :doc:`Email Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index 247c546582ea..26c137079a93 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -8,8 +8,8 @@ Upgrade Encryption Documentations ************** -- `Encryption Library Documentation CodeIgniter 3.X `_ -- :doc:`Encryption Service Documentation CodeIgniter 4.X ` +- `Encryption Library Documentation CodeIgniter 3.x `_ +- :doc:`Encryption Service Documentation CodeIgniter 4.x ` What has been changed ********************* diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index adb200b9f0f7..8b9c6bc78789 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -7,8 +7,8 @@ Upgrade Working with Uploaded Files Documentations ============== -- `File Uploading Class Documentation CodeIgniter 3.X `_ -- :doc:`Working with Uploaded Files Documentation CodeIgniter 4.X ` +- `File Uploading Class Documentation CodeIgniter 3.x `_ +- :doc:`Working with Uploaded Files Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index 09059e547abe..a8bd56fe5977 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -8,8 +8,8 @@ Upgrade HTML Tables Documentations ============== -- `HTML Table Documentation CodeIgniter 3.X `_ -- :doc:`HTML Table Documentation CodeIgniter 4.X ` +- `HTML Table Documentation CodeIgniter 3.x `_ +- :doc:`HTML Table Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_images.rst b/user_guide_src/source/installation/upgrade_images.rst new file mode 100644 index 000000000000..c10d6398a596 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_images.rst @@ -0,0 +1,42 @@ +Upgrade Image Manipulation Class +################################ + +.. contents:: + :local: + :depth: 2 + +Documentations +============== + +- `Image Manipulation Class Documentation CodeIgniter 3.x `_ +- :doc:`Image Manipulation Class Documentation CodeIgniter 4.x <../libraries/images>` + +What has been changed +===================== +- The preferences passed to the constructor or ``initialize()`` method in CI3 + have been changed to be specified in the new methods in CI4. +- Some preferences like ``create_thumb`` are removed. +- In CI4, the ``save()`` method must be called to save the manipulated image. +- The ``display_errors()`` has been removed, and an exception will be thrown + if an error occurs. + +Upgrade Guide +============= +1. Within your class change the ``$this->load->library('image_lib');`` to + ``$image = \Config\Services::image();``. +2. Change the preferences passed to the constructor or ``initialize()`` method + to be specified in the corresponding methods. +3. Call the ``save()`` method to save the file. + +Code Example +============ + +CodeIgniter Version 3.x +------------------------ + +.. literalinclude:: upgrade_images/ci3sample/001.php + +CodeIgniter Version 4.x +----------------------- + +.. literalinclude:: upgrade_images/001.php diff --git a/user_guide_src/source/installation/upgrade_images/001.php b/user_guide_src/source/installation/upgrade_images/001.php new file mode 100644 index 000000000000..c40e9b8076a9 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_images/001.php @@ -0,0 +1,8 @@ +withFile('/path/to/image/mypic.jpg') + ->resize(75, 50, true) + ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/installation/upgrade_images/ci3sample/001.php b/user_guide_src/source/installation/upgrade_images/ci3sample/001.php new file mode 100644 index 000000000000..94a8553a5e2a --- /dev/null +++ b/user_guide_src/source/installation/upgrade_images/ci3sample/001.php @@ -0,0 +1,12 @@ +load->library('image_lib', $config); + +$this->image_lib->resize(); diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index d962eb462fd4..589dd57ec669 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -8,8 +8,8 @@ Upgrade Localization Documentations ============== -- `Language Documentation CodeIgniter 3.X `_ -- :doc:`Localization Documentation CodeIgniter 4.X ` +- `Language Documentation CodeIgniter 3.x `_ +- :doc:`Localization Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 67d826863968..0936c48ad400 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -8,8 +8,8 @@ Upgrade Migrations Documentations ============== -- `Database Migrations Documentation CodeIgniter 3.X `_ -- :doc:`Database Migrations Documentation CodeIgniter 4.X ` +- `Database Migrations Documentation CodeIgniter 3.x `_ +- :doc:`Database Migrations Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index bc5fbf08292f..a47cd8fc8ae3 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -8,8 +8,8 @@ Upgrade Models Documentations ============== -- `Model Documentation CodeIgniter 3.X `_ -- :doc:`Model Documentation CodeIgniter 4.X ` +- `Model Documentation CodeIgniter 3.x `_ +- :doc:`Model Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 69e19d57164c..a53a60f52ca2 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -8,8 +8,8 @@ Upgrade Pagination Documentations ============== -- `Pagination Class Documentation CodeIgniter 3.X `_ -- :doc:`Pagination Documentation CodeIgniter 4.X ` +- `Pagination Class Documentation CodeIgniter 3.x `_ +- :doc:`Pagination Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index 2059647b230d..26ccfc658e3f 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -7,8 +7,8 @@ Upgrade HTTP Responses Documentations ============== -- `Output Class Documentation CodeIgniter 3.X `_ -- :doc:`HTTP Responses Documentation CodeIgniter 4.X ` +- `Output Class Documentation CodeIgniter 3.x `_ +- :doc:`HTTP Responses Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 83bc5c5ee8a5..6dfe13e1e965 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -8,8 +8,8 @@ Upgrade Routing Documentations ============== -- `URI Routing Documentation CodeIgniter 3.X `_ -- :doc:`URI Routing Documentation CodeIgniter 4.X ` +- `URI Routing Documentation CodeIgniter 3.x `_ +- :doc:`URI Routing Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 81bf5e290d56..c84fb071adb1 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -8,8 +8,8 @@ Upgrade Security Documentations ============== -- `Security Class Documentation CodeIgniter 3.X `_ -- :doc:`Security Documentation CodeIgniter 4.X ` +- `Security Class Documentation CodeIgniter 3.x `_ +- :doc:`Security Documentation CodeIgniter 4.x ` .. note:: If you use the :doc:`../helpers/form_helper` and enable the CSRF filter globally, then :php:func:`form_open()` will automatically insert a hidden CSRF field in your forms. So you do not have to upgrade this by yourself. diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index ecc27360f310..d03b1c465267 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -8,8 +8,8 @@ Upgrade Sessions Documentations ============== -- `Session Library Documentation CodeIgniter 3.X `_ -- :doc:`Session Library Documentation CodeIgniter 4.X ` +- `Session Library Documentation CodeIgniter 3.x `_ +- :doc:`Session Library Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 7f42cf8e1f70..116bc2e48d59 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -8,8 +8,8 @@ Upgrade Validations Documentations of Library ========================= -- `Form Validation Documentation CodeIgniter 3.X `_ -- :doc:`Validation Documentation CodeIgniter 4.X ` +- `Form Validation Documentation CodeIgniter 3.x `_ +- :doc:`Validation Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index c58aeb8dd491..1464e7e4d5b0 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -8,8 +8,8 @@ Upgrade View Parser Documentations ============== -- `Template Parser Documentation CodeIgniter 3.X `_ -- :doc:`View Parser Documentation CodeIgniter 4.X ` +- `Template Parser Documentation CodeIgniter 3.x `_ +- :doc:`View Parser Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 09ffa427d33c..9b2e4867a804 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -8,8 +8,8 @@ Upgrade Views Documentations ============== -- `View Documentation CodeIgniter 3.X `_ -- :doc:`View Documentation CodeIgniter 4.X ` +- `View Documentation CodeIgniter 3.x `_ +- :doc:`View Documentation CodeIgniter 4.x ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 3b29315d4eab..1ba301af1e33 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -16,6 +16,7 @@ See also :doc:`./backward_compatibility_notes`. backward_compatibility_notes + upgrade_448 upgrade_447 upgrade_446 upgrade_445 diff --git a/user_guide_src/source/libraries/images.rst b/user_guide_src/source/libraries/images.rst index 0507c5d36529..08efccfe92f9 100644 --- a/user_guide_src/source/libraries/images.rst +++ b/user_guide_src/source/libraries/images.rst @@ -49,14 +49,15 @@ Regardless of the type of processing you would like to perform (resizing, cropping, rotation, or watermarking), the general process is identical. You will set some preferences corresponding to the action you intend to perform, then call one of the available processing functions. + For example, to create an image thumbnail you'll do this: .. literalinclude:: images/003.php The above code tells the library to look for an image -called *mypic.jpg* located in the source_image folder, then create a -new image from it that is 100 x 100pixels using the GD2 image_library, -and save it to a new file (the thumb). Since it is using the ``fit()`` method, +called **mypic.jpg** located in the **/path/to/image** folder, then create a +new image from it that is 100 x 100 pixels, +and save it to a new file **mypic_thumb.jpg**. Since it is using the ``fit()`` method, it will attempt to find the best portion of the image to crop based on the desired aspect ratio, and then crop and resize the result. @@ -68,7 +69,7 @@ previous results: .. literalinclude:: images/004.php This example would take the same image and first fix any mobile phone orientation issues, -rotate the image by 90 degrees, and then crop the result into a 100x100 pixel image, +rotate the image by 90 degrees, and then crop the result into a 100 x 100 pixel image, starting at the top left corner. The result would be saved as the thumbnail. .. note:: In order for the image class to be allowed to do any @@ -85,7 +86,7 @@ Image Quality ``save()`` can take an additional parameter ``$quality`` to alter the resulting image quality. Values range from 0 to 100 with 90 being the framework default. This parameter -only applies to JPEG and WEBP images, will be ignored otherwise: +only applies to JPEG and WebP images, will be ignored otherwise: .. note:: The parameter ``$quality`` for WebP can be used since v4.4.0. @@ -135,7 +136,7 @@ thumbnail images that should match a certain size/aspect ratio. This is handled - ``$maintainRatio`` will, if true, adjust the final dimensions as needed to maintain the image's original aspect ratio. - ``$masterDim`` specifies which dimension should be left untouched when ``$maintainRatio`` is true. Values can be: ``'width'``, ``'height'``, or ``'auto'``. -To take a 50x50 pixel square out of the center of an image, you would need to first calculate the appropriate x and y +To take a 50 x 50 pixel square out of the center of an image, you would need to first calculate the appropriate x and y offset values: .. literalinclude:: images/008.php @@ -231,7 +232,7 @@ The ``rotate()`` method allows you to rotate an image in 90 degree increments:: - ``$angle`` is the number of degrees to rotate. One of ``90``, ``180``, ``270``. .. note:: While the ``$angle`` parameter accepts a float, it will convert it to an integer during the process. - If the value is any other than the three values listed above, it will throw a CodeIgniter\Images\ImageException. + If the value is any other than the three values listed above, it will throw a ``CodeIgniter\Images\ImageException``. Adding a Text Watermark ======================= @@ -251,17 +252,17 @@ that allow you to specify how the text should be displayed: The possible options that are recognized are as follows: -- ``color`` Text Color (hex number), i.e., #ff0000 -- ``opacity`` A number between 0 and 1 that represents the opacity of the text. +- ``color`` Text Color (hex number), i.e., ``'#ff0000'`` +- ``opacity`` A number between ``0`` and ``1`` that represents the opacity of the text. - ``withShadow`` Boolean value whether to display a shadow or not. - ``shadowColor`` Color of the shadow (hex number) - ``shadowOffset`` How many pixels to offset the shadow. Applies to both the vertical and horizontal values. -- ``hAlign`` Horizontal alignment: left, center, right -- ``vAlign`` Vertical alignment: top, middle, bottom +- ``hAlign`` Horizontal alignment: ``'left'``, ``'center'``, ``'right'`` +- ``vAlign`` Vertical alignment: ``'top'``, ``'middle'``, ``'bottom'`` - ``hOffset`` Additional offset on the x axis, in pixels - ``vOffset`` Additional offset on the y axis, in pixels - ``fontPath`` The full server path to the TTF font you wish to use. System font will be used if none is given. -- ``fontSize`` The font size to use. When using the GD handler with the system font, valid values are between 1-5. +- ``fontSize`` The font size to use. When using the GD handler with the system font, valid values are between ``1`` to ``5``. .. note:: The ImageMagick driver does not recognize full server path for fontPath. Instead, simply provide the name of one of the installed system fonts that you wish to use, i.e., Calibri. diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 560706c2b73f..118af85e86ee 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -5,8 +5,8 @@ Working with Uploaded Files CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES`` array directly. This extends the :doc:`File class ` and thus gains all of the features of that class. -.. note:: This is not the same as the File Uploading class in CodeIgniter v3.x. This provides a raw - interface to the uploaded files with a few small features. +.. note:: This is not the same as the File Uploading class in CodeIgniter 3. + This provides a raw interface to the uploaded files with a few small features. .. contents:: :local: @@ -309,7 +309,7 @@ getClientPath() .. versionadded:: 4.4.0 -Returns the `webkit relative path `_ of the uploaded file when the client has uploaded files via directory upload. +Returns the `webkit relative path `_ of the uploaded file when the client has uploaded files via directory upload. In PHP versions below 8.1, this returns ``null`` .. literalinclude:: uploaded_files/023.php diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 41a754bc25ee..ce561e0be810 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -151,6 +151,8 @@ configured to any name of your choice by using `$deletedField`_ property. .. important:: The ``deleted_at`` field in the database must be nullable. +.. _model-allowed-fields: + $allowedFields -------------- diff --git a/user_guide_src/source/models/model/003.php b/user_guide_src/source/models/model/003.php index 1b70cea84a84..c2ef0d257efc 100644 --- a/user_guide_src/source/models/model/003.php +++ b/user_guide_src/source/models/model/003.php @@ -6,6 +6,8 @@ class UserModel extends UserAuthModel { + // ... + /** * Called during initialization. Appends * our custom field to the module's model. diff --git a/user_guide_src/source/models/model/004.php b/user_guide_src/source/models/model/004.php index 1ae028acbf7a..1005e6f7f2e7 100644 --- a/user_guide_src/source/models/model/004.php +++ b/user_guide_src/source/models/model/004.php @@ -7,4 +7,6 @@ class UserModel extends Model { protected $DBGroup = 'group_name'; + + // ... } diff --git a/user_guide_src/source/models/model/027.php b/user_guide_src/source/models/model/027.php index 3a039df49465..86a5a5f4c71a 100644 --- a/user_guide_src/source/models/model/027.php +++ b/user_guide_src/source/models/model/027.php @@ -6,6 +6,8 @@ class UserModel extends Model { + // ... + protected $validationRules = [ 'username' => 'required|max_length[30]|alpha_numeric_space|min_length[3]', 'email' => 'required|max_length[254]|valid_email|is_unique[users.email]', diff --git a/user_guide_src/source/models/model/034.php b/user_guide_src/source/models/model/034.php index b18544ee555e..ac8989263ee2 100644 --- a/user_guide_src/source/models/model/034.php +++ b/user_guide_src/source/models/model/034.php @@ -6,5 +6,7 @@ class UserModel extends Model { + // ... + protected $validationRules = 'users'; } diff --git a/user_guide_src/source/models/model/038.php b/user_guide_src/source/models/model/038.php index 5ed40baae0eb..2e61e1fc94f8 100644 --- a/user_guide_src/source/models/model/038.php +++ b/user_guide_src/source/models/model/038.php @@ -6,6 +6,8 @@ class MyModel extends Model { + // ... + protected $validationRules = [ 'id' => 'max_length[19]|is_natural_no_zero', 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]', diff --git a/user_guide_src/source/models/model/040.php b/user_guide_src/source/models/model/040.php index df4d628d1c9d..94de0d042171 100644 --- a/user_guide_src/source/models/model/040.php +++ b/user_guide_src/source/models/model/040.php @@ -6,6 +6,8 @@ class MyModel extends Model { + // ... + protected $validationRules = [ 'id' => 'max_length[19]|is_natural_no_zero', 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,4]', diff --git a/user_guide_src/source/models/model/041.php b/user_guide_src/source/models/model/041.php index 94ad48e0effb..d5b73ec3869e 100644 --- a/user_guide_src/source/models/model/041.php +++ b/user_guide_src/source/models/model/041.php @@ -6,5 +6,7 @@ class MyModel extends Model { + // ... + protected $allowedFields = ['name', 'email', 'address']; } diff --git a/user_guide_src/source/models/model/050.php b/user_guide_src/source/models/model/050.php index 9f6d334609f1..5f5a4fdb7278 100644 --- a/user_guide_src/source/models/model/050.php +++ b/user_guide_src/source/models/model/050.php @@ -6,6 +6,8 @@ class MyModel extends Model { + // ... + protected function hashPassword(array $data) { if (! isset($data['data']['password'])) { diff --git a/user_guide_src/source/models/model/051.php b/user_guide_src/source/models/model/051.php index 0ca5ee317a37..28229e22edcb 100644 --- a/user_guide_src/source/models/model/051.php +++ b/user_guide_src/source/models/model/051.php @@ -6,6 +6,10 @@ class MyModel extends Model { + // ... + protected $beforeInsert = ['hashPassword']; protected $beforeUpdate = ['hashPassword']; + + // ... } diff --git a/user_guide_src/source/models/model/052.php b/user_guide_src/source/models/model/052.php index 292b752bdc3c..d049e938c713 100644 --- a/user_guide_src/source/models/model/052.php +++ b/user_guide_src/source/models/model/052.php @@ -6,5 +6,9 @@ class MyModel extends Model { + // ... + protected $allowCallbacks = false; + + // ... } diff --git a/user_guide_src/source/models/model/054.php b/user_guide_src/source/models/model/054.php index 6b72095f087f..c67b4828acfd 100644 --- a/user_guide_src/source/models/model/054.php +++ b/user_guide_src/source/models/model/054.php @@ -6,6 +6,8 @@ class MyModel extends Model { + // ... + protected $beforeFind = ['checkCache']; // ... diff --git a/user_guide_src/source/outgoing/alternative_php.rst b/user_guide_src/source/outgoing/alternative_php.rst index b4a2b10257e5..742c59d404c8 100644 --- a/user_guide_src/source/outgoing/alternative_php.rst +++ b/user_guide_src/source/outgoing/alternative_php.rst @@ -15,11 +15,11 @@ Alternative Echos Normally to echo, or print out a variable you would do this:: - + With the alternative syntax you can instead do it this way:: - + Alternative Control Structures ============================== diff --git a/user_guide_src/source/outgoing/alternative_php/001.php b/user_guide_src/source/outgoing/alternative_php/001.php index 9158fe27dccc..b9c543ef4211 100644 --- a/user_guide_src/source/outgoing/alternative_php/001.php +++ b/user_guide_src/source/outgoing/alternative_php/001.php @@ -2,7 +2,7 @@ -
  • +
  • diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index f84e9b029004..3e611ceab2ec 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -104,12 +104,19 @@ Setting the Current Locale If you want to set the locale directly, you may use ``IncomingRequest::setLocale(string $locale)``. -You must set supported locales in **app/Config/App.php**: + +Before setting the locale, you must set valid locales. Because any attempt to +set a locale that are not valid will result in +the :ref:`default locale ` being set. + +By default, the valid locales are defined in ``Config\App::$supportedLocales`` +in **app/Config/App.php**: .. literalinclude:: localization/003.php -.. note:: Any attempt to set a locale not included in this array will result in - the :ref:`default locale ` being set. +.. note:: Since v4.4.0, ``IncomingRequest::setValidLocales()`` has been added to + set (and reset) valid locales. Use it if you want to change the valid locales + dynamically. Retrieving the Current Locale ============================= diff --git a/writable/.htaccess b/writable/.htaccess index f24db0accc73..3462048add78 100755 --- a/writable/.htaccess +++ b/writable/.htaccess @@ -1,6 +1,6 @@ - Require all denied + Require all denied - Deny from all + Deny from all