Skip to content

refactor: update CheckPhpIni code #9672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 44 additions & 29 deletions system/Security/CheckPhpIni.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<string, array{global: string, current: string, recommended: string, remark: string}> $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'] !== '') {
Expand All @@ -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<string, array{global: string, current: string, recommended: string, remark: string}> $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;
Expand All @@ -95,27 +109,27 @@ private static function outputForWeb(array $output, array $thead, array $tbody):
$directive = $notRecommended
? '<span style="color: red">' . $directive . '</span>'
: $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 border="1" cellpadding="4" cellspacing="0">',
];
$table->setTemplate($template);

$table = new Table();
$table->setTemplate(['table_open' => '<table border="1" cellpadding="4" cellspacing="0">']);
$table->setHeading($thead);

return '<pre>' . $table->generate($tbody) . '</pre>';
}

/**
* @internal Used for testing purposes only.
* @testTag
* @return array<string, array{global: string, current: string, recommended: string, remark: string}>
*/
public static function checkIni(?string $argument = null): array
private static function checkIni(?string $argument = null): array
{
// Default items
$items = [
Expand Down Expand Up @@ -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);
Expand All @@ -173,7 +189,6 @@ public static function checkIni(?string $argument = null): array
];
}

// [directive => [current_value, recommended_value]]
return $output;
}
}
52 changes: 31 additions & 21 deletions tests/system/Security/CheckPhpIniTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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(
'/<table border="1" cellpadding="4" cellspacing="0">/',
$output,
);
$this->assertMatchesRegularExpression(
'/<th>Directive<\/th><th>Global<\/th><th>Current<\/th><th>Recommended<\/th><th>Remark<\/th>/',
$output,
);
$this->assertMatchesRegularExpression(
'/<td>default_charset<\/td><td>UTF-8<\/td><td>UTF-8<\/td><td>UTF-8<\/td><td><\/td>/',
$output,
);
}
}
2 changes: 1 addition & 1 deletion utils/phpstan-baseline/loader.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# total 2844 errors
# total 2837 errors
includes:
- argument.type.neon
- assign.propertyType.neon
Expand Down
37 changes: 1 addition & 36 deletions utils/phpstan-baseline/missingType.iterableValue.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# total 1416 errors
# total 1409 errors

parameters:
ignoreErrors:
Expand Down Expand Up @@ -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
Expand Down
Loading