1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* |
5
|
|
|
* This file is part of the Apix Project. |
6
|
|
|
* |
7
|
|
|
* (c) Franck Cassedanne <franck at ouarz.net> |
8
|
|
|
* |
9
|
|
|
* @license http://opensource.org/licenses/BSD-3-Clause New BSD License |
10
|
|
|
* |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace Apix\Console; |
14
|
|
|
|
15
|
|
|
use Apix\Console, |
16
|
|
|
Apix\Server; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* SystemCheck Console class. |
20
|
|
|
* |
21
|
|
|
* @codeCoverageIgnore |
22
|
|
|
*/ |
23
|
|
|
class SystemCheck extends Console |
24
|
|
|
{ |
25
|
|
|
|
26
|
|
View Code Duplication |
public function help() |
|
|
|
|
27
|
|
|
{ |
28
|
|
|
$args = $this->getArgs(); |
29
|
|
|
$args[0] = 'php ' . $args[0]; |
30
|
|
|
|
31
|
|
|
$this->outRegex( |
32
|
|
|
<<<HELP |
33
|
|
|
<bold>Usage:</bold> <brown>{$args[0]}</brown> [OPTIONS]\r\n |
34
|
|
|
<bold>Options:</bold>\r |
35
|
|
|
--all\t<brown>Run all the checks</brown>\r |
36
|
|
|
--required\t<brown>Run only the required checks</brown>\r |
37
|
|
|
--optionals\t<brown>Run only the optionals checks</brown>\r |
38
|
|
|
--no-colors\t<brown>Don't use colors in the outputs</brown>\r |
39
|
|
|
--verbose <brown>\tAdd some verbosity to the outputs</brown>\r |
40
|
|
|
--help <brown>|</brown> -h\t<brown>Display this help</brown>\n\n |
41
|
|
|
HELP |
42
|
|
|
); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
public function run() |
46
|
|
|
{ |
47
|
|
|
if ( ! $this->hasArgs(array('--no-credits')) ) { |
48
|
|
|
$this->out( |
49
|
|
|
sprintf( |
50
|
|
|
"Apix System Check %s by Franck Cassedanne.\n\n", |
51
|
|
|
Server::VERSION |
52
|
|
|
) |
53
|
|
|
); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
if ( ! $this->hasArgs(array('--required', '--optionals', '--all')) ) { |
57
|
|
|
$this->help(); |
58
|
|
|
exit; |
|
|
|
|
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
$this->out("Checking your system...\n\n", 'bold'); |
62
|
|
|
|
63
|
|
|
if ( !$this->hasArgs(array('--required', '--optionals')) ) { |
64
|
|
|
$this->args[] = '--all'; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
$required = $this->getRequired(); |
68
|
|
|
$this->display( |
69
|
|
|
'Minimum requirements (required to pass): ', |
70
|
|
|
$required, |
71
|
|
|
array('--required', '--all') |
72
|
|
|
); |
73
|
|
|
|
74
|
|
|
$this->out(PHP_EOL . PHP_EOL); |
75
|
|
|
|
76
|
|
|
$optionals = $this->getOptionals(); |
77
|
|
|
$this->display( |
78
|
|
|
'Optionals (recommended to pass): ', |
79
|
|
|
$optionals, |
80
|
|
|
array('--optionals', '--all') |
81
|
|
|
); |
82
|
|
|
|
83
|
|
|
$this->out(PHP_EOL.PHP_EOL); |
84
|
|
|
|
85
|
|
|
if ($this->hasArgs(array('--required', '--optionals'))) { |
86
|
|
|
exit; |
|
|
|
|
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
$req = false; |
90
|
|
|
foreach ($required as $k=>$v) { |
91
|
|
|
if($v['fail'] === true) $req = true; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
$opt = false; |
95
|
|
|
foreach ($optionals as $k=>$v) { |
96
|
|
|
if($v['fail'] === true) $opt = true; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
if ($req) { |
100
|
|
|
$summary = "<red>Warning!</red> "; |
101
|
|
|
$summary .= "Minimum system requirements not met. Good luck."; |
102
|
|
|
} elseif ($opt) { |
103
|
|
|
$summary = "<green>Well done.</green> Except to a few optionals, "; |
104
|
|
|
$summary .= "your system is ready."; |
105
|
|
|
} else { |
106
|
|
|
$summary = "This system is fine. "; |
107
|
|
|
$summary .= "<green>Well done, you are ready to roll.</green>"; |
108
|
|
|
} |
109
|
|
|
$br = "<dark_grey>-----------------------------------------------------------------------</dark_grey>"; |
110
|
|
|
$this->outRegex("${br}\n\n ${summary}\n\n${br}\n"); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
public function display($title, array $checks, array $args) |
114
|
|
|
{ |
115
|
|
|
$this->out($title); |
116
|
|
|
if ( $this->hasArgs($args) ) { |
117
|
|
|
foreach ($checks as $key => $check) { |
118
|
|
|
$this->out(PHP_EOL); |
119
|
|
|
$this->check($key, $check); |
120
|
|
|
} |
121
|
|
|
} else { |
122
|
|
|
$this->out('skipped, not in the run.', 'failed'); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
public function check($key, $check) |
127
|
|
|
{ |
128
|
|
|
$this->out(' [ ', 'brown'); |
129
|
|
|
if ($check['fail'] !== true) { |
130
|
|
|
$this->out('pass', 'green'); |
131
|
|
|
} else { |
132
|
|
|
$this->out('fail', 'on_red'); |
133
|
|
|
} |
134
|
|
|
$this->out(" ] - {$key}", 'brown'); |
135
|
|
|
|
136
|
|
|
if ($check['fail'] !== true) { |
137
|
|
|
if ($this->verbose > 0 && isset($check['verbose'])) { |
138
|
|
|
$this->out(sprintf(' / %s', $check['verbose'])); |
139
|
|
|
} |
140
|
|
|
} else { |
141
|
|
|
foreach ($check['msgs'] as $msg) { |
142
|
|
|
$this->out(PHP_EOL); |
143
|
|
|
$this->out(' '); |
144
|
|
|
$this->out($msg, 'failed'); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
public function getRequired() |
150
|
|
|
{ |
151
|
|
|
$suhosin = ini_get('suhosin.executor.include.whitelist'); |
152
|
|
|
|
153
|
|
|
$required = array( |
154
|
|
|
'PHP version > 5.3.2' => array( |
155
|
|
|
'fail' => version_compare(PHP_VERSION, '5.3.2', '<'), |
156
|
|
|
'verbose' => PHP_VERSION . ' installed', |
157
|
|
|
'msgs' => array( |
158
|
|
|
"The version of PHP (".PHP_VERSION.") installed is too old.", |
159
|
|
|
"You must upgrade to PHP 5.3.2 or higher." |
160
|
|
|
) |
161
|
|
|
), |
162
|
|
|
'Phar support' => array( |
163
|
|
|
'fail' => !extension_loaded('Phar'), |
164
|
|
|
'verbose' => 'on', |
165
|
|
|
'msgs' =>array( |
166
|
|
|
"The phar extension is missing.", |
167
|
|
|
"Install it or recompile PHP without using --disable-phar" |
168
|
|
|
) |
169
|
|
|
), |
170
|
|
|
'zlib' => array( |
171
|
|
|
'fail' => !extension_loaded('zlib'), |
172
|
|
|
'verbose' => 'on', |
173
|
|
|
'msgs' => array( |
174
|
|
|
"The zlib extension is required.", |
175
|
|
|
"Install it or recompile PHP with --with-zlib" |
176
|
|
|
) |
177
|
|
|
), |
178
|
|
|
'Suhosin' => array( |
179
|
|
|
'fail' => false !== $suhosin |
180
|
|
|
&& false === stripos($suhosin, 'phar'), |
181
|
|
|
'verbose' => 'off or whitelisted', |
182
|
|
|
'msgs' => array( |
183
|
|
|
"The suhosin.executor.include.whitelist setting is incorrect.", |
184
|
|
|
"Add the following to the end of your 'php.ini' or 'suhosin.ini':", |
185
|
|
|
" suhosin.executor.include.whitelist = phar " . $suhosin |
186
|
|
|
) |
187
|
|
|
), |
188
|
|
|
'detect_unicode' => array( |
189
|
|
|
'fail' => ini_get('detect_unicode'), |
190
|
|
|
'verbose' => 'off', |
191
|
|
|
'msgs' => array( |
192
|
|
|
"This setting must be disabled.", |
193
|
|
|
"Add the following to the end of your 'php.ini':", |
194
|
|
|
" detect_unicode = Off" |
195
|
|
|
) |
196
|
|
|
), |
197
|
|
|
'allow_url_fopen' => array( |
198
|
|
|
'fail' => !ini_get('allow_url_fopen'), |
199
|
|
|
'verbose' => 'on', |
200
|
|
|
'msgs' => array( |
201
|
|
|
"The allow_url_fopen setting is incorrect.", |
202
|
|
|
"Add the following to the end of your 'php.ini':", |
203
|
|
|
" allow_url_fopen = On" |
204
|
|
|
) |
205
|
|
|
), |
206
|
|
|
'ionCube loader disabled' => array( |
207
|
|
|
'fail' => extension_loaded('ionCube Loader'), |
208
|
|
|
'verbose' => 'off', |
209
|
|
|
'msgs' => array( |
210
|
|
|
"The ionCube Loader extension could be incompatible with Phar files.", |
211
|
|
|
"Anything prior to 4.0.9 will not work too well with Phar archives.", |
212
|
|
|
"Consider upgrading to 4.0.9 or newer OR comment the 'ioncube_loader_lin_5.3.so' line from your 'php.ini'." |
213
|
|
|
) |
214
|
|
|
) |
215
|
|
|
); |
216
|
|
|
|
217
|
|
|
return $required; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
public function getOptionals() |
221
|
|
|
{ |
222
|
|
|
// sigchild |
223
|
|
|
ob_start(); |
224
|
|
|
phpinfo(INFO_GENERAL); |
225
|
|
|
$phpinfo = ob_get_clean(); |
226
|
|
|
preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $config); |
227
|
|
|
|
228
|
|
|
$optionals = array( |
229
|
|
|
// APC |
230
|
|
|
'apc_cli disabled' => array( |
231
|
|
|
'fail' => ini_get('apc.enable_cli'), |
232
|
|
|
'msgs' => array( |
233
|
|
|
"The apc.enable_cli should be set to Off.", |
234
|
|
|
"Add the following to your 'php.ini':", |
235
|
|
|
" apc.enable_cli = Off" |
236
|
|
|
), |
237
|
|
|
), |
238
|
|
|
|
239
|
|
|
// sigchild |
240
|
|
|
'sigchild' => array( |
241
|
|
|
'fail' => false !== strpos($config[1], '--enable-sigchild'), |
242
|
|
|
'msgs' => array( |
243
|
|
|
"PHP was compiled with --enable-sigchild which can cause issues on some platforms.", |
244
|
|
|
"Recompile it without this flag if possible, see also:", |
245
|
|
|
" https://bugs.php.net/bug.php?id=22999" |
246
|
|
|
) |
247
|
|
|
), |
248
|
|
|
|
249
|
|
|
// tidy |
250
|
|
|
'Tidy' => array( |
251
|
|
|
'fail' => !extension_loaded('tidy'), |
252
|
|
|
'msgs' => array( |
253
|
|
|
"The Tidy extension is use for validating html/xml.", |
254
|
|
|
) |
255
|
|
|
), |
256
|
|
|
|
257
|
|
|
// PHP > 5.4 |
258
|
|
|
'PHP version > 5.4' => array( |
259
|
|
|
'fail' => version_compare(PHP_VERSION, '5.4.0', '<'), |
260
|
|
|
'msgs' => array( |
261
|
|
|
"PHP 5.4 introduces lots of nifty additions and is generally faster.", |
262
|
|
|
"You should consider upgrading to PHP 5.4 or higher." |
263
|
|
|
) |
264
|
|
|
), |
265
|
|
|
); |
266
|
|
|
|
267
|
|
|
return $optionals; |
268
|
|
|
} |
269
|
|
|
public function out($msg=null, $styles=null) |
270
|
|
|
{ |
271
|
|
|
if (null !== $msg) { |
272
|
|
|
$software_name = 'apix-server'; |
273
|
|
|
$msg = str_replace("{software.name}", $software_name, $msg); |
274
|
|
|
|
275
|
|
|
switch ($styles): |
276
|
|
|
case 'error': |
277
|
|
|
parent::out($msg, 'red'); |
278
|
|
|
break; |
279
|
|
|
|
280
|
|
|
case 'info': |
281
|
|
|
parent::out($msg, 'green'); |
282
|
|
|
break; |
283
|
|
|
|
284
|
|
|
case 'success': |
285
|
|
|
parent::out($msg, 'black', 'green'); |
286
|
|
|
break; |
287
|
|
|
|
288
|
|
|
case 'failed': |
289
|
|
|
parent::out($msg, 'black', 'red'); |
290
|
|
|
break; |
291
|
|
|
|
292
|
|
|
default: |
293
|
|
|
parent::out(func_get_args()); |
294
|
|
|
endswitch; |
295
|
|
|
} else { |
296
|
|
|
parent::out(func_get_args()); |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
} |
301
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.