Merge pull request #17719 from civicrm/5.27
[civicrm-core.git] / Civi / Install / Requirements.php
CommitLineData
d7dea16c
EM
1<?php
2
3namespace Civi\Install;
4
5/**
6 * Class Requirements
7 * @package Civi\Install
8 */
9class Requirements {
10
11 /**
12 * Requirement severity -- Requirement successfully met.
13 */
14 const REQUIREMENT_OK = 0;
15
16 /**
17 * Requirement severity -- Warning condition; proceed but flag warning.
18 */
19 const REQUIREMENT_WARNING = 1;
20
21 /**
22 * Requirement severity -- Error condition; abort installation.
23 */
24 const REQUIREMENT_ERROR = 2;
25
34f3bbd9
SL
26 /**
27 * @var array
28 */
c64f69d9 29 protected $system_checks = [
d7dea16c
EM
30 'checkMemory',
31 'checkServerVariables',
32 'checkMysqlConnectExists',
33 'checkJsonEncodeExists',
9ad2ba41 34 'checkMultibyteExists',
c64f69d9 35 ];
d7dea16c 36
c64f69d9 37 protected $database_checks = [
d7dea16c
EM
38 'checkMysqlConnection',
39 'checkMysqlVersion',
40 'checkMysqlInnodb',
41 'checkMysqlTempTables',
42 'checkMySQLAutoIncrementIncrementOne',
43 'checkMysqlTrigger',
44 'checkMysqlThreadStack',
45 'checkMysqlLockTables',
75615982 46 'checkMysqlUtf8mb4',
c64f69d9 47 ];
d7dea16c
EM
48
49 /**
50 * Run all requirements tests.
51 *
52 * @param array $config
53 * An array with two keys:
54 * - file_paths
55 * - db_config
56 *
a6c01b45
CW
57 * @return array
58 * An array of check summaries. Each array contains the keys 'title', 'severity', and 'details'.
d7dea16c
EM
59 */
60 public function checkAll(array $config) {
6ef58b18
SL
61 if (!class_exists('\CRM_Utils_SQL_TempTable')) {
62 require_once dirname(__FILE__) . '/../../CRM/Utils/SQL/TempTable.php';
63 }
d7dea16c
EM
64 return array_merge($this->checkSystem($config['file_paths']), $this->checkDatabase($config['db_config']));
65 }
66
67 /**
68 * Check system requirements are met, such as sufficient memory,
69 * necessary file paths are writable and required php extensions
70 * are available.
71 *
72 * @param array $file_paths
73 * An array of file paths that will be checked to confirm they
74 * are writable.
75 *
76 * @return array
77 */
78 public function checkSystem(array $file_paths) {
c64f69d9 79 $errors = [];
d7dea16c
EM
80
81 $errors[] = $this->checkFilepathIsWritable($file_paths);
82 foreach ($this->system_checks as $check) {
83 $errors[] = $this->$check();
84 }
85
86 return $errors;
87 }
88
89 /**
90 * Check database connection, database version and other
91 * database requirements are met.
92 *
93 * @param array $db_config
94 * An array with keys:
95 * - host (with optional port specified eg. localhost:12345)
16b10e64 96 * - database (name of database to select)
d7dea16c
EM
97 * - username
98 * - password
99 *
100 * @return array
101 */
102 public function checkDatabase(array $db_config) {
c64f69d9 103 $errors = [];
d7dea16c
EM
104
105 foreach ($this->database_checks as $check) {
106 $errors[] = $this->$check($db_config);
107 }
108
109 return $errors;
110 }
111
9043c4bf
SL
112 /**
113 * Generates a mysql connection
114 *
34f3bbd9 115 * @param $db_config array
9043c4bf
SL
116 * @return object mysqli connection
117 */
118 protected function connect($db_config) {
3916ca43
SL
119 $host = NULL;
120 if (!empty($db_config['host'])) {
121 $host = $db_config['host'];
122 }
123 elseif (!empty($db_config['server'])) {
124 $host = $db_config['server'];
125 }
126 $conn = @mysqli_connect($host, $db_config['username'], $db_config['password'], $db_config['database'], !empty($db_config['port']) ? $db_config['port'] : NULL);
127 return $conn;
9043c4bf
SL
128 }
129
d7dea16c 130 /**
fe482240 131 * Check configured php Memory.
d7dea16c
EM
132 * @return array
133 */
134 public function checkMemory() {
135 $min = 1024 * 1024 * 32;
136 $recommended = 1024 * 1024 * 64;
137
138 $mem = $this->getPHPMemory();
139 $mem_string = ini_get('memory_limit');
140
c64f69d9 141 $results = [
d7dea16c
EM
142 'title' => 'CiviCRM memory check',
143 'severity' => $this::REQUIREMENT_OK,
144 'details' => "You have $mem_string allocated (minimum 32Mb, recommended 64Mb)",
c64f69d9 145 ];
d7dea16c
EM
146
147 if ($mem < $min && $mem > 0) {
148 $results['severity'] = $this::REQUIREMENT_ERROR;
149 }
4c9b6178 150 elseif ($mem < $recommended && $mem != 0) {
d7dea16c
EM
151 $results['severity'] = $this::REQUIREMENT_WARNING;
152 }
4c9b6178 153 elseif ($mem == 0) {
d7dea16c
EM
154 $results['details'] = "Cannot determine PHP memory allocation. Install only if you're sure you've allocated at least 32 MB.";
155 $results['severity'] = $this::REQUIREMENT_WARNING;
156 }
157
158 return $results;
159 }
160
161 /**
fe482240 162 * Get Configured PHP memory.
d7dea16c
EM
163 * @return float
164 */
165 protected function getPHPMemory() {
166 $memString = ini_get("memory_limit");
167
168 switch (strtolower(substr($memString, -1))) {
169 case "k":
170 return round(substr($memString, 0, -1) * 1024);
ea100cb5 171
d7dea16c
EM
172 case "m":
173 return round(substr($memString, 0, -1) * 1024 * 1024);
ea100cb5 174
d7dea16c
EM
175 case "g":
176 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
ea100cb5 177
d7dea16c
EM
178 default:
179 return round($memString);
180 }
181 }
182
183 /**
184 * @return array
185 */
00be9182 186 public function checkServerVariables() {
c64f69d9 187 $results = [
d7dea16c
EM
188 'title' => 'CiviCRM PHP server variables',
189 'severity' => $this::REQUIREMENT_OK,
190 'details' => 'The required $_SERVER variables are set',
c64f69d9 191 ];
d7dea16c 192
c64f69d9
CW
193 $required_variables = ['SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME'];
194 $missing = [];
d7dea16c
EM
195
196 foreach ($required_variables as $required_variable) {
197 if (empty($_SERVER[$required_variable])) {
198 $missing[] = '$_SERVER[' . $required_variable . ']';
199 }
200 }
201
202 if ($missing) {
203 $results['severity'] = $this::REQUIREMENT_ERROR;
204 $results['details'] = 'The following PHP variables are not set: ' . implode(', ', $missing);
205 }
206
207 return $results;
208 }
209
210 /**
211 * @return array
212 */
213 public function checkJsonEncodeExists() {
c64f69d9 214 $results = [
d7dea16c
EM
215 'title' => 'CiviCRM JSON encoding support',
216 'severity' => $this::REQUIREMENT_OK,
217 'details' => 'Function json_encode() found',
c64f69d9 218 ];
d7dea16c
EM
219 if (!function_exists('json_encode')) {
220 $results['severity'] = $this::REQUIREMENT_ERROR;
221 $results['details'] = 'Function json_encode() does not exist';
222 }
223
224 return $results;
225 }
226
9ad2ba41
SL
227 /**
228 * CHeck that PHP Multibyte functions are enabled.
229 * @return array
230 */
231 public function checkMultibyteExists() {
c64f69d9 232 $results = [
9ad2ba41
SL
233 'title' => 'CiviCRM MultiByte encoding support',
234 'severity' => $this::REQUIREMENT_OK,
235 'details' => 'PHP Multibyte etension found',
c64f69d9 236 ];
9ad2ba41
SL
237 if (!function_exists('mb_substr')) {
238 $results['severity'] = $this::REQUIREMENT_ERROR;
239 $results['details'] = 'PHP Multibyte extension has not been installed and enabled';
240 }
241
242 return $results;
243 }
244
d7dea16c
EM
245 /**
246 * @return array
247 */
248 public function checkMysqlConnectExists() {
c64f69d9 249 $results = [
d7dea16c
EM
250 'title' => 'CiviCRM MySQL check',
251 'severity' => $this::REQUIREMENT_OK,
fcf908c6 252 'details' => 'Function mysqli_connect() found',
c64f69d9 253 ];
fcf908c6 254 if (!function_exists('mysqli_connect')) {
d7dea16c 255 $results['severity'] = $this::REQUIREMENT_ERROR;
fcf908c6 256 $results['details'] = 'Function mysqli_connect() does not exist';
d7dea16c
EM
257 }
258
259 return $results;
260 }
261
262 /**
263 * @param array $db_config
264 *
265 * @return array
266 */
267 public function checkMysqlConnection(array $db_config) {
c64f69d9 268 $results = [
d7dea16c
EM
269 'title' => 'CiviCRM MySQL connection',
270 'severity' => $this::REQUIREMENT_OK,
271 'details' => "Connected",
c64f69d9 272 ];
d7dea16c 273
9043c4bf 274 $conn = $this->connect($db_config);
d7dea16c
EM
275
276 if (!$conn) {
fcf908c6 277 $results['details'] = mysqli_connect_error();
d7dea16c
EM
278 $results['severity'] = $this::REQUIREMENT_ERROR;
279 return $results;
280 }
281
fcf908c6 282 if (!@mysqli_select_db($conn, $db_config['database'])) {
283 $results['details'] = mysqli_error($conn);
d7dea16c
EM
284 $results['severity'] = $this::REQUIREMENT_ERROR;
285 return $results;
286 }
287
288 return $results;
289 }
290
291 /**
292 * @param array $db_config
293 *
294 * @return array
295 */
296 public function checkMysqlVersion(array $db_config) {
010e8b6c 297 $min = \CRM_Upgrade_Incremental_General::MIN_INSTALL_MYSQL_VER;
c64f69d9 298 $results = [
d7dea16c
EM
299 'title' => 'CiviCRM MySQL Version',
300 'severity' => $this::REQUIREMENT_OK,
c64f69d9 301 ];
d7dea16c 302
9043c4bf 303 $conn = $this->connect($db_config);
fcf908c6 304 if (!$conn || !($info = mysqli_get_server_info($conn))) {
d7dea16c
EM
305 $results['severity'] = $this::REQUIREMENT_WARNING;
306 $results['details'] = "Cannot determine the version of MySQL installed. Please ensure at least version {$min} is installed.";
307 return $results;
308 }
309
66c0d0bd
SL
310 $versionDetails = mysqli_query($conn, 'SELECT version() as version')->fetch_assoc();
311 if (version_compare($versionDetails['version'], $min) == -1) {
d7dea16c
EM
312 $results['severity'] = $this::REQUIREMENT_ERROR;
313 $results['details'] = "MySQL version is {$info}; minimum required is {$min}";
314 return $results;
315 }
316
317 $results['details'] = "MySQL version is {$info}";
318 return $results;
319 }
320
321 /**
322 * @param array $db_config
323 *
324 * @return array
325 */
326 public function checkMysqlInnodb(array $db_config) {
c64f69d9 327 $results = [
d7dea16c
EM
328 'title' => 'CiviCRM InnoDB support',
329 'severity' => $this::REQUIREMENT_ERROR,
87a890cc 330 'details' => 'Could not determine if MySQL has InnoDB support. Assuming none.',
c64f69d9 331 ];
d7dea16c 332
9043c4bf 333 $conn = $this->connect($db_config);
d7dea16c
EM
334 if (!$conn) {
335 return $results;
336 }
337
338 $innodb_support = FALSE;
fcf908c6 339 $result = mysqli_query($conn, "SHOW ENGINES");
340 while ($values = mysqli_fetch_array($result)) {
d7dea16c
EM
341 if ($values['Engine'] == 'InnoDB') {
342 if (strtolower($values['Support']) == 'yes' || strtolower($values['Support']) == 'default') {
343 $innodb_support = TRUE;
344 break;
345 }
346 }
347 }
348
349 if ($innodb_support) {
350 $results['severity'] = $this::REQUIREMENT_OK;
351 $results['details'] = 'MySQL supports InnoDB';
352 }
353 return $results;
354 }
355
356 /**
357 * @param array $db_config
358 *
359 * @return array
360 */
361 public function checkMysqlTempTables(array $db_config) {
c64f69d9 362 $results = [
d7dea16c
EM
363 'title' => 'CiviCRM MySQL Temp Tables',
364 'severity' => $this::REQUIREMENT_OK,
365 'details' => 'MySQL server supports temporary tables',
c64f69d9 366 ];
d7dea16c 367
9043c4bf 368 $conn = $this->connect($db_config);
d7dea16c
EM
369 if (!$conn) {
370 $results['severity'] = $this::REQUIREMENT_ERROR;
371 $results['details'] = "Could not connect to database";
372 return $results;
373 }
374
fcf908c6 375 if (!@mysqli_select_db($conn, $db_config['database'])) {
d7dea16c
EM
376 $results['severity'] = $this::REQUIREMENT_ERROR;
377 $results['details'] = "Could not select the database";
378 return $results;
379 }
6ef58b18
SL
380 $temporaryTableName = \CRM_Utils_SQL_TempTable::build()->setCategory('install')->getName();
381 $r = mysqli_query($conn, 'CREATE TEMPORARY TABLE ' . $temporaryTableName . ' (test text)');
d7dea16c
EM
382 if (!$r) {
383 $results['severity'] = $this::REQUIREMENT_ERROR;
384 $results['details'] = "Database does not support creation of temporary tables";
385 return $results;
386 }
387
6ef58b18 388 mysqli_query($conn, 'DROP TEMPORARY TABLE ' . $temporaryTableName);
d7dea16c
EM
389 return $results;
390 }
391
392 /**
393 * @param $db_config
394 *
395 * @return array
396 */
397 public function checkMysqlTrigger($db_config) {
c64f69d9 398 $results = [
d7dea16c
EM
399 'title' => 'CiviCRM MySQL Trigger',
400 'severity' => $this::REQUIREMENT_OK,
401 'details' => 'Database supports MySQL triggers',
c64f69d9 402 ];
d7dea16c 403
9043c4bf 404 $conn = $this->connect($db_config);
d7dea16c
EM
405 if (!$conn) {
406 $results['severity'] = $this::REQUIREMENT_ERROR;
407 $results['details'] = 'Could not connect to database';
408 return $results;
409 }
410
fcf908c6 411 if (!@mysqli_select_db($conn, $db_config['database'])) {
d7dea16c
EM
412 $results['severity'] = $this::REQUIREMENT_ERROR;
413 $results['details'] = "Could not select the database";
414 return $results;
415 }
416
fcf908c6 417 $r = mysqli_query($conn, 'CREATE TABLE civicrm_install_temp_table_test (test text)');
d7dea16c
EM
418 if (!$r) {
419 $results['severity'] = $this::REQUIREMENT_ERROR;
420 $results['details'] = 'Could not create a table to run test';
421 return $results;
422 }
423
fcf908c6 424 $r = mysqli_query($conn, 'CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
d7dea16c
EM
425 if (!$r) {
426 $results['severity'] = $this::REQUIREMENT_ERROR;
427 $results['details'] = 'Database does not support creation of triggers';
428 }
429 else {
fcf908c6 430 mysqli_query($conn, 'DROP TRIGGER civicrm_install_temp_table_test_trigger');
d7dea16c
EM
431 }
432
fcf908c6 433 mysqli_query($conn, 'DROP TABLE civicrm_install_temp_table_test');
d7dea16c
EM
434 return $results;
435 }
436
437 /**
438 * @param array $db_config
439 *
440 * @return array
441 */
442 public function checkMySQLAutoIncrementIncrementOne(array $db_config) {
c64f69d9 443 $results = [
d7dea16c
EM
444 'title' => 'CiviCRM MySQL AutoIncrementIncrement',
445 'severity' => $this::REQUIREMENT_OK,
446 'details' => 'MySQL server auto_increment_increment is 1',
c64f69d9 447 ];
d7dea16c 448
9043c4bf 449 $conn = $this->connect($db_config);
d7dea16c
EM
450 if (!$conn) {
451 $results['severity'] = $this::REQUIREMENT_ERROR;
452 $results['details'] = 'Could not connect to database';
453 return $results;
454 }
455
fcf908c6 456 $r = mysqli_query($conn, "SHOW variables like 'auto_increment_increment'");
d7dea16c
EM
457 if (!$r) {
458 $results['severity'] = $this::REQUIREMENT_ERROR;
459 $results['details'] = 'Could not query database server variables';
460 return $results;
461 }
462
fcf908c6 463 $values = mysqli_fetch_row($r);
d7dea16c
EM
464 if ($values[1] != 1) {
465 $results['severity'] = $this::REQUIREMENT_ERROR;
466 $results['details'] = 'MySQL server auto_increment_increment is not 1';
467 }
468 return $results;
469 }
470
471 /**
472 * @param $db_config
473 *
474 * @return array
475 */
476 public function checkMysqlThreadStack($db_config) {
477 $min_thread_stack = 192;
478
c64f69d9 479 $results = [
d7dea16c
EM
480 'title' => 'CiviCRM Mysql thread stack',
481 'severity' => $this::REQUIREMENT_OK,
482 'details' => 'MySQL thread_stack is OK',
c64f69d9 483 ];
d7dea16c 484
9043c4bf 485 $conn = $this->connect($db_config);
d7dea16c
EM
486 if (!$conn) {
487 $results['severity'] = $this::REQUIREMENT_ERROR;
488 $results['details'] = 'Could not connect to database';
489 return $results;
490 }
491
fcf908c6 492 if (!@mysqli_select_db($conn, $db_config['database'])) {
d7dea16c
EM
493 $results['severity'] = $this::REQUIREMENT_ERROR;
494 $results['details'] = 'Could not select the database';
495 return $results;
496 }
497
34f3bbd9
SL
498 // bytes => kb
499 $r = mysqli_query($conn, "SHOW VARIABLES LIKE 'thread_stack'");
d7dea16c
EM
500 if (!$r) {
501 $results['severity'] = $this::REQUIREMENT_ERROR;
502 $results['details'] = 'Could not query thread_stack value';
503 }
504 else {
fcf908c6 505 $values = mysqli_fetch_row($r);
d7dea16c
EM
506 if ($values[1] < (1024 * $min_thread_stack)) {
507 $results['severity'] = $this::REQUIREMENT_ERROR;
508 $results['details'] = 'MySQL thread_stack is ' . ($values[1] / 1024) . "kb (minimum required is {$min_thread_stack} kb";
509 }
510 }
511
512 return $results;
513 }
514
515 /**
516 * @param $db_config
517 *
518 * @return array
519 */
00be9182 520 public function checkMysqlLockTables($db_config) {
c64f69d9 521 $results = [
d7dea16c
EM
522 'title' => 'CiviCRM MySQL Lock Tables',
523 'severity' => $this::REQUIREMENT_OK,
524 'details' => 'Can successfully lock and unlock tables',
c64f69d9 525 ];
d7dea16c 526
9043c4bf 527 $conn = $this->connect($db_config);
d7dea16c
EM
528 if (!$conn) {
529 $results['severity'] = $this::REQUIREMENT_ERROR;
46bcf597 530 $results['details'] = 'Could not connect to database';
d7dea16c
EM
531 return $results;
532 }
533
fcf908c6 534 if (!@mysqli_select_db($conn, $db_config['database'])) {
d7dea16c
EM
535 $results['severity'] = $this::REQUIREMENT_ERROR;
536 $results['details'] = 'Could not select the database';
fcf908c6 537 mysqli_close($conn);
d7dea16c
EM
538 return $results;
539 }
540
fcf908c6 541 $r = mysqli_query($conn, 'CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)');
d7dea16c
EM
542 if (!$r) {
543 $results['severity'] = $this::REQUIREMENT_ERROR;
544 $results['details'] = 'Could not create a table';
fcf908c6 545 mysqli_close($conn);
d7dea16c
EM
546 return $results;
547 }
548
fcf908c6 549 $r = mysqli_query($conn, 'LOCK TABLES civicrm_install_temp_table_test WRITE');
d7dea16c
EM
550 if (!$r) {
551 $results['severity'] = $this::REQUIREMENT_ERROR;
552 $results['details'] = 'Could not obtain a write lock';
fcf908c6 553 mysqli_close($conn);
d7dea16c
EM
554 return $results;
555 }
556
fcf908c6 557 $r = mysqli_query($conn, 'UNLOCK TABLES');
d7dea16c
EM
558 if (!$r) {
559 $results['severity'] = $this::REQUIREMENT_ERROR;
560 $results['details'] = 'Could not release table lock';
561 }
562
fcf908c6 563 mysqli_close($conn);
d7dea16c
EM
564 return $results;
565 }
566
567 /**
568 * @param $file_paths
569 *
570 * @return array
571 */
572 public function checkFilepathIsWritable($file_paths) {
c64f69d9 573 $results = [
d7dea16c
EM
574 'title' => 'CiviCRM directories are writable',
575 'severity' => $this::REQUIREMENT_OK,
576 'details' => 'All required directories are writable: ' . implode(', ', $file_paths),
c64f69d9 577 ];
d7dea16c 578
c64f69d9 579 $unwritable_dirs = [];
d7dea16c
EM
580 foreach ($file_paths as $path) {
581 if (!is_writable($path)) {
582 $unwritable_dirs[] = $path;
583 }
584 }
585
586 if ($unwritable_dirs) {
587 $results['severity'] = $this::REQUIREMENT_ERROR;
588 $results['details'] = "The following directories need to be made writable by the webserver: " . implode(', ', $unwritable_dirs);
589 }
590
591 return $results;
592 }
96025800 593
75615982 594 /**
595 * @param $db_config
596 *
597 * @return array
598 */
599 public function checkMysqlUtf8mb4($db_config) {
c64f69d9 600 $results = [
75615982 601 'title' => 'CiviCRM MySQL utf8mb4 Support',
602 'severity' => $this::REQUIREMENT_OK,
603 'details' => 'Your system supports the MySQL utf8mb4 character set.',
c64f69d9 604 ];
75615982 605
606 $conn = $this->connect($db_config);
607 if (!$conn) {
608 $results['severity'] = $this::REQUIREMENT_ERROR;
609 $results['details'] = 'Could not connect to database';
610 return $results;
611 }
612
613 if (!@mysqli_select_db($conn, $db_config['database'])) {
614 $results['severity'] = $this::REQUIREMENT_ERROR;
615 $results['details'] = 'Could not select the database';
616 mysqli_close($conn);
617 return $results;
618 }
619
50169eb4 620 mysqli_query($conn, 'DROP TABLE IF EXISTS civicrm_utf8mb4_test');
75615982 621 $r = mysqli_query($conn, 'CREATE TABLE civicrm_utf8mb4_test (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB');
622 if (!$r) {
623 $results['severity'] = $this::REQUIREMENT_WARNING;
624 $results['details'] = 'It is recommended, though not yet required, to configure your MySQL server for utf8mb4 support. You will need the following MySQL server configuration: innodb_large_prefix=true innodb_file_format=barracuda innodb_file_per_table=true';
625 mysqli_close($conn);
626 return $results;
627 }
50169eb4 628 mysqli_query($conn, 'DROP TABLE civicrm_utf8mb4_test');
75615982 629
630 // Ensure that the MySQL driver supports utf8mb4 encoding.
e479ac61 631 $version = mysqli_get_client_info();
75615982 632 if (strpos($version, 'mysqlnd') !== FALSE) {
633 // The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
634 $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
635 if (version_compare($version, '5.0.9', '<')) {
636 $results['severity'] = $this::REQUIREMENT_WARNING;
637 $results['details'] = 'It is recommended, though not yet required, to upgrade your PHP MySQL driver (mysqlnd) to >= 5.0.9 for utf8mb4 support.';
638 mysqli_close($conn);
639 return $results;
640 }
641 }
642 else {
643 // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
644 if (version_compare($version, '5.5.3', '<')) {
645 $results['severity'] = $this::REQUIREMENT_WARNING;
646 $results['details'] = 'It is recommended, though not yet required, to upgrade your PHP MySQL driver (libmysqlclient) to >= 5.5.3 for utf8mb4 support.';
647 mysqli_close($conn);
648 return $results;
649 }
650 }
651
652 mysqli_close($conn);
653 return $results;
654 }
655
d7dea16c 656}