Skip to content

feat: add spark command to check php.ini #8581

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 6 commits into from
Mar 2, 2024
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
2 changes: 2 additions & 0 deletions deptrac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ parameters:
- CodeIgniter\HTTP\URI
CodeIgniter\Log\Handlers\ChromeLoggerHandler:
- CodeIgniter\HTTP\ResponseInterface
CodeIgniter\Security\CheckPhpIni:
- CodeIgniter\View\Table
CodeIgniter\View\Table:
- CodeIgniter\Database\BaseResult
CodeIgniter\View\Plugins:
Expand Down
77 changes: 77 additions & 0 deletions system/Commands/Utilities/PhpIniCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Commands\Utilities;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\Security\CheckPhpIni;

/**
* Check php.ini values.
*/
final class PhpIniCheck extends BaseCommand
{
/**
* The group the command is lumped under
* when listing commands.
*
* @var string
*/
protected $group = 'CodeIgniter';

/**
* The Command's name
*
* @var string
*/
protected $name = 'phpini:check';

/**
* The Command's short description
*
* @var string
*/
protected $description = 'Check your php.ini values.';

/**
* The Command's usage
*
* @var string
*/
protected $usage = 'phpini:check';

/**
* The Command's arguments
*
* @var array<string, string>
*/
protected $arguments = [
];

/**
* The Command's options
*
* @var array<string, string>
*/
protected $options = [];

/**
* {@inheritDoc}
*/
public function run(array $params)
{
CheckPhpIni::run();

return EXIT_SUCCESS;
}
}
155 changes: 155 additions & 0 deletions system/Security/CheckPhpIni.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php

declare(strict_types=1);

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Security;

use CodeIgniter\CLI\CLI;
use CodeIgniter\View\Table;

/**
* Checks php.ini settings
*
* @used-by \CodeIgniter\Commands\Utilities\PhpIniCheck
* @see \CodeIgniter\Security\CheckPhpIniTest
*/
class CheckPhpIni
{
/**
* @param bool $isCli Set false if you run via Web
*
* @return string|void HTML string or void in CLI
*/
public static function run(bool $isCli = true)
{
$output = static::checkIni();

$thead = ['Directive', 'Global', 'Current', 'Recommended', 'Remark'];
$tbody = [];

// CLI
if ($isCli) {
self::outputForCli($output, $thead, $tbody);

return;
}

// Web
return self::outputForWeb($output, $thead, $tbody);
}

private static function outputForCli(array $output, array $thead, array $tbody): void
{
foreach ($output as $directive => $values) {
$current = $values['current'];
$notRecommended = false;

if ($values['recommended'] !== '') {
if ($values['recommended'] !== $values['current']) {
$notRecommended = true;
}

$current = $notRecommended
? CLI::color($values['current'] === '' ? 'n/a' : $values['current'], 'red')
: $values['current'];
}

$directive = $notRecommended ? CLI::color($directive, 'red') : $directive;
$tbody[] = [
$directive, $values['global'], $current, $values['recommended'], $values['remark'],
];
}

CLI::table($tbody, $thead);
}

private static function outputForWeb(array $output, array $thead, array $tbody): string
{
foreach ($output as $directive => $values) {
$current = $values['current'];
$notRecommended = false;

if ($values['recommended'] !== '') {
if ($values['recommended'] !== $values['current']) {
$notRecommended = true;
}

if ($values['current'] === '') {
$current = 'n/a';
}

$current = $notRecommended
? '<span style="color: red">' . $current . '</span>'
: $current;
}

$directive = $notRecommended
? '<span style="color: red">' . $directive . '</span>'
: $directive;
$tbody[] = [
$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->setHeading($thead);

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

/**
* @internal Used for testing purposes only.
* @testTag
*/
public static function checkIni(): array
{
$items = [
'error_reporting' => ['recommended' => '5111'],
'display_errors' => ['recommended' => '0'],
'display_startup_errors' => ['recommended' => '0'],
'log_errors' => [],
'error_log' => [],
'default_charset' => ['recommended' => 'UTF-8'],
'memory_limit' => ['remark' => '> post_max_size'],
'post_max_size' => ['remark' => '> upload_max_filesize'],
'upload_max_filesize' => ['remark' => '< post_max_size'],
'request_order' => ['recommended' => 'GP'],
'variables_order' => ['recommended' => 'GPCS'],
'date.timezone' => ['recommended' => 'UTC'],
'mbstring.language' => ['recommended' => 'neutral'],
'opcache.enable' => ['recommended' => '1'],
'opcache.enable_cli' => [],
'opcache.jit' => [],
'opcache.jit_buffer_size' => [],
];

$output = [];
$ini = ini_get_all();

foreach ($items as $key => $values) {
$output[$key] = [
'global' => $ini[$key]['global_value'],
'current' => $ini[$key]['local_value'],
'recommended' => $values['recommended'] ?? '',
'remark' => $values['remark'] ?? '',
];
}

// [directive => [current_value, recommended_value]]
return $output;
}
}
63 changes: 63 additions & 0 deletions tests/system/Security/CheckPhpIniTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Security;

use CodeIgniter\CLI\CLI;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockInputOutput;

/**
* @internal
*
* @group Others
*/
final class CheckPhpIniTest extends CIUnitTestCase
{
public function testCheckIni()
{
$output = CheckPhpIni::checkIni();

$expected = [
'global' => '',
'current' => '1',
'recommended' => '0',
'remark' => '',
];
$this->assertSame($expected, $output['display_errors']);
}

public function testRunCli()
{
// 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();
}

public function testRunWeb()
{
$output = CheckPhpIni::run(false);

$this->assertStringContainsString('display_errors', $output);
}
}
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Commands
:ref:`cli-generators-make-test` for the details.
- Added ``spark config:check`` command to check Config values. See
:ref:`confirming-config-values` for the details.
- Added ``spark phpini:check`` command to check important PHP ini settings. See
:ref:`spark-phpini-check` for the details.
- Added ``spark lang:find`` command to update translations keys. See :ref:`generating-translation-files-via-command` for the details.
- The ``--dbgroup`` option has been added to the ``spark db:table`` command.
See :ref:`Database Commands <db-command-specify-the-dbgroup>`.
Expand Down
41 changes: 41 additions & 0 deletions user_guide_src/source/installation/running.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,47 @@ you will need to modify the permissions for the **writable** folder inside
your project, so that it is writable by the user or account used by your
web server.

.. _spark-phpini-check:

Checking PHP ini Settings
=========================

.. versionadded:: 4.5.0

`PHP ini settings`_ change the behaviors of PHP. CodeIgniter provides a command to
check important PHP settings.

.. _PHP ini settings: https://www.php.net/manual/en/ini.list.php

.. code-block:: console

php spark phpini:check

The *Recommended* column shows the recommended values for production environment.
They may differ in development environments.

.. note::
If you cannot use the spark command, you can use ``CheckPhpIni::run(false)``
in your controller.

E.g.,

.. code-block:: php

<?php

namespace App\Controllers;

use CodeIgniter\Security\CheckPhpIni;

class Home extends BaseController
{
public function index(): string
{
return CheckPhpIni::run(false);
}
}

************************
Local Development Server
************************
Expand Down