diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 4ce5e25fbc..c0cf8d8fd7 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -28,8 +28,6 @@ $finder = Finder::create() 'ThirdParty', 'Validation/Views', ]) - ->notPath([ - ]) ->notName('#Foobar.php$#') ->append([ __FILE__, @@ -41,12 +39,7 @@ $finder = Finder::create() __DIR__ . '/spark', ]); -$overrides = [ - // for updating to coding-standard - 'modernize_strpos' => true, - 'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha'], - 'php_unit_attributes' => true, -]; +$overrides = []; $options = [ 'cacheFile' => 'build/.php-cs-fixer.cache', diff --git a/.php-cs-fixer.no-header.php b/.php-cs-fixer.no-header.php index e7d9647e31..f3bc97dc78 100644 --- a/.php-cs-fixer.no-header.php +++ b/.php-cs-fixer.no-header.php @@ -11,12 +11,12 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -use CodeIgniter\CodingStandard\CodeIgniter4; -use Nexus\CsConfig\Factory; -use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\FixerGenerator; +use PhpCsFixer\ConfigInterface; use PhpCsFixer\Finder; +/** @var ConfigInterface $config */ +$config = require __DIR__ . '/.php-cs-fixer.dist.php'; + $finder = Finder::create() ->files() ->in([ @@ -30,19 +30,10 @@ $finder = Finder::create() ]); $overrides = [ - // for updating to coding-standard - 'modernize_strpos' => true, - 'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha'], - 'php_unit_attributes' => true, + 'header_comment' => false, ]; -$options = [ - 'cacheFile' => 'build/.php-cs-fixer.no-header.cache', - 'finder' => $finder, - 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), - 'customRules' => [ - NoCodeSeparatorCommentFixer::name() => true, - ], -]; - -return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); +return $config + ->setFinder($finder) + ->setCacheFile('build/.php-cs-fixer.no-header.cache') + ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/.php-cs-fixer.tests.php b/.php-cs-fixer.tests.php index 1b4bfd71e3..28a7124909 100644 --- a/.php-cs-fixer.tests.php +++ b/.php-cs-fixer.tests.php @@ -11,47 +11,29 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -use CodeIgniter\CodingStandard\CodeIgniter4; -use Nexus\CsConfig\Factory; -use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\FixerGenerator; +use PhpCsFixer\ConfigInterface; use PhpCsFixer\Finder; +/** @var ConfigInterface $config */ +$config = require __DIR__ . '/.php-cs-fixer.dist.php'; + $finder = Finder::create() ->files() ->in([ __DIR__ . '/tests', ]) - ->exclude([ - ]) ->notPath([ '_support/View/Cells/multiplier.php', '_support/View/Cells/colors.php', '_support/View/Cells/addition.php', ]) - ->notName('#Foobar.php$#') - ->append([ - ]); + ->notName('#Foobar.php$#'); $overrides = [ 'void_return' => true, - // for updating to coding-standard - 'modernize_strpos' => true, - 'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha'], - 'php_unit_attributes' => true, ]; -$options = [ - 'cacheFile' => 'build/.php-cs-fixer.tests.cache', - 'finder' => $finder, - 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), - 'customRules' => [ - NoCodeSeparatorCommentFixer::name() => true, - ], -]; - -return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary( - 'CodeIgniter 4 framework', - 'CodeIgniter Foundation', - 'admin@codeigniter.com' -); +return $config + ->setFinder($finder) + ->setCacheFile('build/.php-cs-fixer.tests.cache') + ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/.php-cs-fixer.user-guide.php b/.php-cs-fixer.user-guide.php index 3be7cd45c7..6b925ee8b0 100644 --- a/.php-cs-fixer.user-guide.php +++ b/.php-cs-fixer.user-guide.php @@ -11,12 +11,12 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -use CodeIgniter\CodingStandard\CodeIgniter4; -use Nexus\CsConfig\Factory; -use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\FixerGenerator; +use PhpCsFixer\ConfigInterface; use PhpCsFixer\Finder; +/** @var ConfigInterface $config */ +$config = require __DIR__ . '/.php-cs-fixer.dist.php'; + $finder = Finder::create() ->files() ->in([ @@ -32,6 +32,7 @@ $finder = Finder::create() $overrides = [ 'echo_tag_syntax' => false, + 'header_comment' => false, 'php_unit_internal_class' => false, 'no_unused_imports' => false, 'class_attributes_separation' => false, @@ -39,19 +40,9 @@ $overrides = [ 'import_symbols' => false, 'leading_backslash_in_global_namespace' => true, ], - // for updating to coding-standard - 'modernize_strpos' => true, - 'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha'], - 'php_unit_attributes' => true, ]; -$options = [ - 'cacheFile' => 'build/.php-cs-fixer.user-guide.cache', - 'finder' => $finder, - 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), - 'customRules' => [ - NoCodeSeparatorCommentFixer::name() => true, - ], -]; - -return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); +return $config + ->setFinder($finder) + ->setCacheFile('build/.php-cs-fixer.user-guide.cache') + ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index 97a92690b9..eec3d25546 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -95,6 +95,7 @@ } h2 { + font-weight: bold; font-size: $base-size; margin: 0; padding: 5px 0 10px 0; @@ -292,6 +293,8 @@ // The tabs container .tab { + height: fit-content; + text-align: left; bottom: 35px; display: none; left: 0; @@ -306,6 +309,8 @@ // The "Timeline" tab .timeline { + position: static; + display: table; margin-left: 0; width: 100%; diff --git a/composer.json b/composer.json index ce3316112c..bd2fe56888 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "phpunit/phpcov": "^9.0.2", "phpunit/phpunit": "^10.5.16", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "1.2.0", + "rector/rector": "1.2.1", "vimeo/psalm": "^5.0" }, "replace": { diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 748ded12b3..fe55527d11 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -7393,12 +7393,6 @@ $ignoreErrors[] = [ 'count' => 1, 'path' => __DIR__ . '/system/Helpers/test_helper.php', ]; -$ignoreErrors[] = [ - // identifier: empty.notAllowed - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Helpers/text_helper.php', -]; $ignoreErrors[] = [ // identifier: missingType.iterableValue 'message' => '#^Function strip_slashes\\(\\) has parameter \\$str with no value type specified in iterable type array\\.$#', diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 2fc079d3c9..0fb4c3c7c3 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -76,6 +76,7 @@ use Config\Modules; use Config\Optimize; use Config\Pager as ConfigPager; use Config\Services as AppServices; +use Config\Session as ConfigSession; use Config\Toolbar as ConfigToolbar; use Config\Validation as ConfigValidation; use Config\View as ConfigView; @@ -130,7 +131,7 @@ use Config\View as ConfigView; * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) * @method static RouteCollection routes($getShared = true) * @method static Security security(App $config = null, $getShared = true) - * @method static Session session(App $config = null, $getShared = true) + * @method static Session session(ConfigSession $config = null, $getShared = true) * @method static SiteURIFactory siteurifactory(App $config = null, Superglobals $superglobals = null, $getShared = true) * @method static Superglobals superglobals(array $server = null, array $get = null, bool $getShared = true) * @method static Throttler throttler($getShared = true) diff --git a/system/Config/Services.php b/system/Config/Services.php index 422799e0b8..e37b1278e9 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -51,6 +51,7 @@ use CodeIgniter\Router\RouteCollection; use CodeIgniter\Router\RouteCollectionInterface; use CodeIgniter\Router\Router; use CodeIgniter\Security\Security; +use CodeIgniter\Session\Handlers\BaseHandler as SessionBaseHandler; use CodeIgniter\Session\Handlers\Database\MySQLiHandler; use CodeIgniter\Session\Handlers\Database\PostgreHandler; use CodeIgniter\Session\Handlers\DatabaseHandler; @@ -88,6 +89,7 @@ use Config\Session as SessionConfig; use Config\Toolbar as ToolbarConfig; use Config\Validation as ValidationConfig; use Config\View as ViewConfig; +use InvalidArgumentException; use Locale; /** @@ -674,17 +676,24 @@ class Services extends BaseService if ($driverName === DatabaseHandler::class) { $DBGroup = $config->DBGroup ?? config(Database::class)->defaultGroup; - $db = Database::connect($DBGroup); - $driver = $db->getPlatform(); + $driverPlatform = Database::connect($DBGroup)->getPlatform(); - if ($driver === 'MySQLi') { + if ($driverPlatform === 'MySQLi') { $driverName = MySQLiHandler::class; - } elseif ($driver === 'Postgre') { + } elseif ($driverPlatform === 'Postgre') { $driverName = PostgreHandler::class; } } + if (! class_exists($driverName) || ! is_a($driverName, SessionBaseHandler::class, true)) { + throw new InvalidArgumentException(sprintf( + 'Invalid session handler "%s" provided.', + $driverName + )); + } + + /** @var SessionBaseHandler $driver */ $driver = new $driverName($config, AppServices::get('request')->getIPAddress()); $driver->setLogger($logger); diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 2e165b825e..b9f13c51ff 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -60,6 +60,7 @@ margin-right: 5px; } #debug-bar h2 { + font-weight: bold; font-size: 16px; margin: 0; padding: 5px 0 10px 0; @@ -213,6 +214,8 @@ white-space: nowrap; } #debug-bar .tab { + height: fit-content; + text-align: left; bottom: 35px; display: none; left: 0; @@ -225,6 +228,8 @@ z-index: 9999; } #debug-bar .timeline { + position: static; + display: table; margin-left: 0; width: 100%; } diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 0bb5ad3ea6..dadc1eff34 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -651,11 +651,12 @@ class CURLRequest extends OutgoingRequest // version if (! empty($config['version'])) { - if ($config['version'] === 1.0) { + $version = sprintf('%.1F', $config['version']); + if ($version === '1.0') { $curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; - } elseif ($config['version'] === 1.1) { + } elseif ($version === '1.1') { $curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1; - } elseif ($config['version'] === 2.0) { + } elseif ($version === '2.0') { $curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0; } } diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 8ce3677b0e..4ad6f3827b 100644 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -311,7 +311,7 @@ if (! function_exists('convert_accented_characters')) { if (! is_array($arrayFrom)) { $config = new ForeignCharacters(); - if (empty($config->characterList) || ! is_array($config->characterList)) { + if ($config->characterList === [] || ! is_array($config->characterList)) { $arrayFrom = []; $arrayTo = []; diff --git a/system/Security/CheckPhpIni.php b/system/Security/CheckPhpIni.php index 4cef565ad7..1e92cdc403 100644 --- a/system/Security/CheckPhpIni.php +++ b/system/Security/CheckPhpIni.php @@ -50,17 +50,17 @@ class CheckPhpIni private static function outputForCli(array $output, array $thead, array $tbody): void { foreach ($output as $directive => $values) { - $current = $values['current']; + $current = $values['current'] ?? ''; $notRecommended = false; if ($values['recommended'] !== '') { - if ($values['recommended'] !== $values['current']) { + if ($values['recommended'] !== $current) { $notRecommended = true; } $current = $notRecommended - ? CLI::color($values['current'] === '' ? 'n/a' : $values['current'], 'red') - : $values['current']; + ? CLI::color($current === '' ? 'n/a' : $current, 'red') + : $current; } $directive = $notRecommended ? CLI::color($directive, 'red') : $directive; diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index 4beaed54bf..8854054a23 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -48,6 +48,9 @@ use CodeIgniter\View\Parser; use Config\App; use Config\Exceptions; use Config\Security as SecurityConfig; +use Config\Session as ConfigSession; +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\PreserveGlobalState; use PHPUnit\Framework\Attributes\RunInSeparateProcess; @@ -260,6 +263,32 @@ final class ServicesTest extends CIUnitTestCase $this->assertInstanceOf(Session::class, $actual); } + #[DataProvider('provideNewSessionInvalid')] + #[PreserveGlobalState(false)] + #[RunInSeparateProcess] + public function testNewSessionWithInvalidHandler(string $driver): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf('Invalid session handler "%s" provided.', $driver)); + + $config = new ConfigSession(); + + $config->driver = $driver; + Services::session($config, false); + } + + /** + * @return iterable + */ + public static function provideNewSessionInvalid(): iterable + { + yield 'just a string' => ['file']; + + yield 'inexistent class' => ['Foo']; + + yield 'other class' => [self::class]; + } + #[PreserveGlobalState(false)] #[RunInSeparateProcess] public function testCallStatic(): void diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index dc48eb621d..f14198be22 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -1227,4 +1227,34 @@ alt-svc: h3=":443"; ma=86400' . "\x0d\x0a\x0d\x0aResponse Body"; $this->assertSame('text/html; charset=UTF-8', $response->getHeaderLine('Content-Type')); } + + public function testHTTPversionAsString(): void + { + $this->request->request('POST', '/post', [ + 'version' => '1.0', + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); + $this->assertSame(CURL_HTTP_VERSION_1_0, $options[CURLOPT_HTTP_VERSION]); + + $this->request->request('POST', '/post', [ + 'version' => '1.1', + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); + $this->assertSame(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]); + + $this->request->request('POST', '/post', [ + 'version' => '2.0', + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); + $this->assertSame(CURL_HTTP_VERSION_2_0, $options[CURLOPT_HTTP_VERSION]); + } } diff --git a/user_guide_src/source/changelogs/v4.5.4.rst b/user_guide_src/source/changelogs/v4.5.4.rst index bf737a99a3..51a9fd74f4 100644 --- a/user_guide_src/source/changelogs/v4.5.4.rst +++ b/user_guide_src/source/changelogs/v4.5.4.rst @@ -30,6 +30,9 @@ Deprecations Bugs Fixed ********** +- **CURLRequest:** Fixed a bug preventing the use of strings for ``version`` in the config array + when making requests. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed.