From c349da17c2a3bf74bd61a8c72646e8d3cda0dfbc Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 12 Aug 2025 01:57:54 +0800 Subject: [PATCH] refactor: update `CheckPhpIni` code --- system/Security/CheckPhpIni.php | 73 +++++++++++-------- tests/system/Security/CheckPhpIniTest.php | 52 +++++++------ utils/phpstan-baseline/loader.neon | 2 +- .../missingType.iterableValue.neon | 37 +--------- 4 files changed, 77 insertions(+), 87 deletions(-) diff --git a/system/Security/CheckPhpIni.php b/system/Security/CheckPhpIni.php index 35431c35af57..949c1d10aa48 100644 --- a/system/Security/CheckPhpIni.php +++ b/system/Security/CheckPhpIni.php @@ -17,7 +17,7 @@ use CodeIgniter\View\Table; /** - * Checks php.ini settings + * Checks php.ini settings in production environment. * * @used-by \CodeIgniter\Commands\Utilities\PhpIniCheck * @see \CodeIgniter\Security\CheckPhpIniTest @@ -27,30 +27,33 @@ class CheckPhpIni /** * @param bool $isCli Set false if you run via Web * - * @return string|null HTML string or void in CLI + * @return ($isCli is true ? null : string) */ public static function run(bool $isCli = true, ?string $argument = null) { - $output = static::checkIni($argument); + $output = self::checkIni($argument); $thead = ['Directive', 'Global', 'Current', 'Recommended', 'Remark']; - $tbody = []; - // CLI if ($isCli) { - self::outputForCli($output, $thead, $tbody); + self::outputForCli($output, $thead); return null; } - // Web - return self::outputForWeb($output, $thead, $tbody); + return self::outputForWeb($output, $thead); } - private static function outputForCli(array $output, array $thead, array $tbody): void + /** + * @param array $output + * @param array{string, string, string, string, string} $thead + */ + private static function outputForCli(array $output, array $thead): void { + $tbody = []; + foreach ($output as $directive => $values) { - $current = $values['current'] ?? ''; + $current = $values['current']; $notRecommended = false; if ($values['recommended'] !== '') { @@ -64,16 +67,27 @@ private static function outputForCli(array $output, array $thead, array $tbody): } $directive = $notRecommended ? CLI::color($directive, 'red') : $directive; - $tbody[] = [ - $directive, $values['global'], $current, $values['recommended'], $values['remark'], + + $tbody[] = [ + $directive, + $values['global'], + $current, + $values['recommended'], + $values['remark'], ]; } CLI::table($tbody, $thead); } - private static function outputForWeb(array $output, array $thead, array $tbody): string + /** + * @param array $output + * @param array{string, string, string, string, string} $thead + */ + private static function outputForWeb(array $output, array $thead): string { + $tbody = []; + foreach ($output as $directive => $values) { $current = $values['current']; $notRecommended = false; @@ -95,27 +109,27 @@ private static function outputForWeb(array $output, array $thead, array $tbody): $directive = $notRecommended ? '' . $directive . '' : $directive; + $tbody[] = [ - $directive, $values['global'], $current, $values['recommended'], $values['remark'], + $directive, + $values['global'], + $current, + $values['recommended'], + $values['remark'], ]; } - $table = new Table(); - $template = [ - 'table_open' => '', - ]; - $table->setTemplate($template); - + $table = new Table(); + $table->setTemplate(['table_open' => '
']); $table->setHeading($thead); return '
' . $table->generate($tbody) . '
'; } /** - * @internal Used for testing purposes only. - * @testTag + * @return array */ - public static function checkIni(?string $argument = null): array + private static function checkIni(?string $argument = null): array { // Default items $items = [ @@ -151,17 +165,19 @@ public static function checkIni(?string $argument = null): array 'opcache.interned_strings_buffer' => ['recommended' => '16'], 'opcache.max_accelerated_files' => ['remark' => 'Adjust based on the number of PHP files in your project (e.g.: find your_project/ -iname \'*.php\'|wc -l)'], 'opcache.max_wasted_percentage' => ['recommended' => '10'], - 'opcache.validate_timestamps' => ['recommended' => '0', 'remark' => 'When you disabled, opcache hold your code into shared memory. Restart webserver needed'], + 'opcache.validate_timestamps' => ['recommended' => '0', 'remark' => 'When disabled, opcache will hold your code into shared memory. Restart webserver as needed'], 'opcache.revalidate_freq' => [], 'opcache.file_cache' => ['remark' => 'Location file caching, It should improve performance when SHM memory is full'], - 'opcache.file_cache_only' => ['remark' => 'Opcode caching in shared memory, Disabled when you using Windows'], - 'opcache.file_cache_fallback' => ['remark' => 'Set enable when you using Windows'], - 'opcache.save_comments' => ['recommended' => '0', 'remark' => 'Enable when you using package require docblock annotation'], + 'opcache.file_cache_only' => ['remark' => 'Opcode caching in shared memory, Disabled when you are using Windows'], + 'opcache.file_cache_fallback' => ['remark' => 'Enable when you are using Windows'], + 'opcache.save_comments' => ['recommended' => '0', 'remark' => 'Enable when your code requires to read docblock annotations at runtime'], ]; } $output = []; - $ini = ini_get_all(); + + $ini = ini_get_all(); + assert(is_array($ini)); foreach ($items as $key => $values) { $hasKeyInIni = array_key_exists($key, $ini); @@ -173,7 +189,6 @@ public static function checkIni(?string $argument = null): array ]; } - // [directive => [current_value, recommended_value]] return $output; } } diff --git a/tests/system/Security/CheckPhpIniTest.php b/tests/system/Security/CheckPhpIniTest.php index c11671728ca5..939f69e4191a 100644 --- a/tests/system/Security/CheckPhpIniTest.php +++ b/tests/system/Security/CheckPhpIniTest.php @@ -13,9 +13,8 @@ namespace CodeIgniter\Security; -use CodeIgniter\CLI\CLI; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Mock\MockInputOutput; +use CodeIgniter\Test\StreamFilterTrait; use PHPUnit\Framework\Attributes\Group; /** @@ -24,53 +23,64 @@ #[Group('Others')] final class CheckPhpIniTest extends CIUnitTestCase { + use StreamFilterTrait; + public function testCheckIni(): void { - $output = CheckPhpIni::checkIni(); + $output = self::getPrivateMethodInvoker(CheckPhpIni::class, 'checkIni')(); $expected = [ - 'global' => '', - 'current' => '1', - 'recommended' => '0', + 'global' => 'UTF-8', + 'current' => 'UTF-8', + 'recommended' => 'UTF-8', 'remark' => '', ]; - $this->assertSame($expected, $output['display_errors']); + $this->assertSame($expected, $output['default_charset']); } public function testCheckIniOpcache(): void { - $output = CheckPhpIni::checkIni('opcache'); + $output = self::getPrivateMethodInvoker(CheckPhpIni::class, 'checkIni')('opcache'); $expected = [ 'global' => '1', 'current' => '1', 'recommended' => '0', - 'remark' => 'Enable when you using package require docblock annotation', + 'remark' => 'Enable when your code requires to read docblock annotations at runtime', ]; $this->assertSame($expected, $output['opcache.save_comments']); } public function testRunCli(): void { - // Set MockInputOutput to CLI. - $io = new MockInputOutput(); - CLI::setInputOutput($io); - CheckPhpIni::run(true); - // Get the whole output string. - $output = $io->getOutput(); - - $this->assertStringContainsString('display_errors', $output); - - // Remove MockInputOutput. - CLI::resetInputOutput(); + $this->assertMatchesRegularExpression( + '/\| Directive\s+\| Global\s+\| Current\s+\| Recommended\s+\| Remark\s+\|/', + $this->getStreamFilterBuffer(), + ); + $this->assertMatchesRegularExpression( + '/\| default_charset\s+\| UTF-8\s+\| UTF-8\s+\| UTF-8\s+\| \s+\|/', + $this->getStreamFilterBuffer(), + ); } public function testRunWeb(): void { $output = CheckPhpIni::run(false); - $this->assertStringContainsString('display_errors', (string) $output); + $this->assertIsString($output); + $this->assertMatchesRegularExpression( + '/
/', + $output, + ); + $this->assertMatchesRegularExpression( + '/
Directive<\/th>Global<\/th>Current<\/th>Recommended<\/th>Remark<\/th>/', + $output, + ); + $this->assertMatchesRegularExpression( + '/default_charset<\/td>UTF-8<\/td>UTF-8<\/td>UTF-8<\/td><\/td>/', + $output, + ); } } diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 3f6faed6d265..a92562caf39d 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 2844 errors +# total 2837 errors includes: - argument.type.neon - assign.propertyType.neon diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index 320af631efbf..b217c6c64cda 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1416 errors +# total 1409 errors parameters: ignoreErrors: @@ -4552,41 +4552,6 @@ parameters: count: 1 path: ../../system/Router/RouterInterface.php - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:checkIni\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForCli\(\) has parameter \$output with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForCli\(\) has parameter \$tbody with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForCli\(\) has parameter \$thead with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForWeb\(\) has parameter \$output with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForWeb\(\) has parameter \$tbody with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - - - message: '#^Method CodeIgniter\\Security\\CheckPhpIni\:\:outputForWeb\(\) has parameter \$thead with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Security/CheckPhpIni.php - - message: '#^Property CodeIgniter\\Session\\Handlers\\BaseHandler\:\:\$savePath type has no value type specified in iterable type array\.$#' count: 1