Skip to content

Commit 4658167

Browse files
authored
Merge pull request #8581 from kenjis/feat-spark-phpini-check
feat: add spark command to check php.ini
2 parents 89f0360 + e966a70 commit 4658167

File tree

6 files changed

+340
-0
lines changed

6 files changed

+340
-0
lines changed

deptrac.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ parameters:
256256
- CodeIgniter\HTTP\URI
257257
CodeIgniter\Log\Handlers\ChromeLoggerHandler:
258258
- CodeIgniter\HTTP\ResponseInterface
259+
CodeIgniter\Security\CheckPhpIni:
260+
- CodeIgniter\View\Table
259261
CodeIgniter\View\Table:
260262
- CodeIgniter\Database\BaseResult
261263
CodeIgniter\View\Plugins:
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Commands\Utilities;
15+
16+
use CodeIgniter\CLI\BaseCommand;
17+
use CodeIgniter\Security\CheckPhpIni;
18+
19+
/**
20+
* Check php.ini values.
21+
*/
22+
final class PhpIniCheck extends BaseCommand
23+
{
24+
/**
25+
* The group the command is lumped under
26+
* when listing commands.
27+
*
28+
* @var string
29+
*/
30+
protected $group = 'CodeIgniter';
31+
32+
/**
33+
* The Command's name
34+
*
35+
* @var string
36+
*/
37+
protected $name = 'phpini:check';
38+
39+
/**
40+
* The Command's short description
41+
*
42+
* @var string
43+
*/
44+
protected $description = 'Check your php.ini values.';
45+
46+
/**
47+
* The Command's usage
48+
*
49+
* @var string
50+
*/
51+
protected $usage = 'phpini:check';
52+
53+
/**
54+
* The Command's arguments
55+
*
56+
* @var array<string, string>
57+
*/
58+
protected $arguments = [
59+
];
60+
61+
/**
62+
* The Command's options
63+
*
64+
* @var array<string, string>
65+
*/
66+
protected $options = [];
67+
68+
/**
69+
* {@inheritDoc}
70+
*/
71+
public function run(array $params)
72+
{
73+
CheckPhpIni::run();
74+
75+
return EXIT_SUCCESS;
76+
}
77+
}

system/Security/CheckPhpIni.php

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Security;
15+
16+
use CodeIgniter\CLI\CLI;
17+
use CodeIgniter\View\Table;
18+
19+
/**
20+
* Checks php.ini settings
21+
*
22+
* @used-by \CodeIgniter\Commands\Utilities\PhpIniCheck
23+
* @see \CodeIgniter\Security\CheckPhpIniTest
24+
*/
25+
class CheckPhpIni
26+
{
27+
/**
28+
* @param bool $isCli Set false if you run via Web
29+
*
30+
* @return string|void HTML string or void in CLI
31+
*/
32+
public static function run(bool $isCli = true)
33+
{
34+
$output = static::checkIni();
35+
36+
$thead = ['Directive', 'Global', 'Current', 'Recommended', 'Remark'];
37+
$tbody = [];
38+
39+
// CLI
40+
if ($isCli) {
41+
self::outputForCli($output, $thead, $tbody);
42+
43+
return;
44+
}
45+
46+
// Web
47+
return self::outputForWeb($output, $thead, $tbody);
48+
}
49+
50+
private static function outputForCli(array $output, array $thead, array $tbody): void
51+
{
52+
foreach ($output as $directive => $values) {
53+
$current = $values['current'];
54+
$notRecommended = false;
55+
56+
if ($values['recommended'] !== '') {
57+
if ($values['recommended'] !== $values['current']) {
58+
$notRecommended = true;
59+
}
60+
61+
$current = $notRecommended
62+
? CLI::color($values['current'] === '' ? 'n/a' : $values['current'], 'red')
63+
: $values['current'];
64+
}
65+
66+
$directive = $notRecommended ? CLI::color($directive, 'red') : $directive;
67+
$tbody[] = [
68+
$directive, $values['global'], $current, $values['recommended'], $values['remark'],
69+
];
70+
}
71+
72+
CLI::table($tbody, $thead);
73+
}
74+
75+
private static function outputForWeb(array $output, array $thead, array $tbody): string
76+
{
77+
foreach ($output as $directive => $values) {
78+
$current = $values['current'];
79+
$notRecommended = false;
80+
81+
if ($values['recommended'] !== '') {
82+
if ($values['recommended'] !== $values['current']) {
83+
$notRecommended = true;
84+
}
85+
86+
if ($values['current'] === '') {
87+
$current = 'n/a';
88+
}
89+
90+
$current = $notRecommended
91+
? '<span style="color: red">' . $current . '</span>'
92+
: $current;
93+
}
94+
95+
$directive = $notRecommended
96+
? '<span style="color: red">' . $directive . '</span>'
97+
: $directive;
98+
$tbody[] = [
99+
$directive, $values['global'], $current, $values['recommended'], $values['remark'],
100+
];
101+
}
102+
103+
$table = new Table();
104+
$template = [
105+
'table_open' => '<table border="1" cellpadding="4" cellspacing="0">',
106+
];
107+
$table->setTemplate($template);
108+
109+
$table->setHeading($thead);
110+
111+
return '<pre>' . $table->generate($tbody) . '</pre>';
112+
}
113+
114+
/**
115+
* @internal Used for testing purposes only.
116+
* @testTag
117+
*/
118+
public static function checkIni(): array
119+
{
120+
$items = [
121+
'error_reporting' => ['recommended' => '5111'],
122+
'display_errors' => ['recommended' => '0'],
123+
'display_startup_errors' => ['recommended' => '0'],
124+
'log_errors' => [],
125+
'error_log' => [],
126+
'default_charset' => ['recommended' => 'UTF-8'],
127+
'memory_limit' => ['remark' => '> post_max_size'],
128+
'post_max_size' => ['remark' => '> upload_max_filesize'],
129+
'upload_max_filesize' => ['remark' => '< post_max_size'],
130+
'request_order' => ['recommended' => 'GP'],
131+
'variables_order' => ['recommended' => 'GPCS'],
132+
'date.timezone' => ['recommended' => 'UTC'],
133+
'mbstring.language' => ['recommended' => 'neutral'],
134+
'opcache.enable' => ['recommended' => '1'],
135+
'opcache.enable_cli' => [],
136+
'opcache.jit' => [],
137+
'opcache.jit_buffer_size' => [],
138+
];
139+
140+
$output = [];
141+
$ini = ini_get_all();
142+
143+
foreach ($items as $key => $values) {
144+
$output[$key] = [
145+
'global' => $ini[$key]['global_value'],
146+
'current' => $ini[$key]['local_value'],
147+
'recommended' => $values['recommended'] ?? '',
148+
'remark' => $values['remark'] ?? '',
149+
];
150+
}
151+
152+
// [directive => [current_value, recommended_value]]
153+
return $output;
154+
}
155+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Security;
15+
16+
use CodeIgniter\CLI\CLI;
17+
use CodeIgniter\Test\CIUnitTestCase;
18+
use CodeIgniter\Test\Mock\MockInputOutput;
19+
20+
/**
21+
* @internal
22+
*
23+
* @group Others
24+
*/
25+
final class CheckPhpIniTest extends CIUnitTestCase
26+
{
27+
public function testCheckIni()
28+
{
29+
$output = CheckPhpIni::checkIni();
30+
31+
$expected = [
32+
'global' => '',
33+
'current' => '1',
34+
'recommended' => '0',
35+
'remark' => '',
36+
];
37+
$this->assertSame($expected, $output['display_errors']);
38+
}
39+
40+
public function testRunCli()
41+
{
42+
// Set MockInputOutput to CLI.
43+
$io = new MockInputOutput();
44+
CLI::setInputOutput($io);
45+
46+
CheckPhpIni::run(true);
47+
48+
// Get the whole output string.
49+
$output = $io->getOutput();
50+
51+
$this->assertStringContainsString('display_errors', $output);
52+
53+
// Remove MockInputOutput.
54+
CLI::resetInputOutput();
55+
}
56+
57+
public function testRunWeb()
58+
{
59+
$output = CheckPhpIni::run(false);
60+
61+
$this->assertStringContainsString('display_errors', $output);
62+
}
63+
}

user_guide_src/source/changelogs/v4.5.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Commands
2828
:ref:`cli-generators-make-test` for the details.
2929
- Added ``spark config:check`` command to check Config values. See
3030
:ref:`confirming-config-values` for the details.
31+
- Added ``spark phpini:check`` command to check important PHP ini settings. See
32+
:ref:`spark-phpini-check` for the details.
3133
- Added ``spark lang:find`` command to update translations keys. See :ref:`generating-translation-files-via-command` for the details.
3234
- The ``--dbgroup`` option has been added to the ``spark db:table`` command.
3335
See :ref:`Database Commands <db-command-specify-the-dbgroup>`.

user_guide_src/source/installation/running.rst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,47 @@ you will need to modify the permissions for the **writable** folder inside
7474
your project, so that it is writable by the user or account used by your
7575
web server.
7676

77+
.. _spark-phpini-check:
78+
79+
Checking PHP ini Settings
80+
=========================
81+
82+
.. versionadded:: 4.5.0
83+
84+
`PHP ini settings`_ change the behaviors of PHP. CodeIgniter provides a command to
85+
check important PHP settings.
86+
87+
.. _PHP ini settings: https://www.php.net/manual/en/ini.list.php
88+
89+
.. code-block:: console
90+
91+
php spark phpini:check
92+
93+
The *Recommended* column shows the recommended values for production environment.
94+
They may differ in development environments.
95+
96+
.. note::
97+
If you cannot use the spark command, you can use ``CheckPhpIni::run(false)``
98+
in your controller.
99+
100+
E.g.,
101+
102+
.. code-block:: php
103+
104+
<?php
105+
106+
namespace App\Controllers;
107+
108+
use CodeIgniter\Security\CheckPhpIni;
109+
110+
class Home extends BaseController
111+
{
112+
public function index(): string
113+
{
114+
return CheckPhpIni::run(false);
115+
}
116+
}
117+
77118
************************
78119
Local Development Server
79120
************************

0 commit comments

Comments
 (0)