3 namespace Civi\Install
;
7 * @package Civi\Install
12 * Requirement severity -- Requirement successfully met.
14 const REQUIREMENT_OK
= 0;
17 * Requirement severity -- Warning condition; proceed but flag warning.
19 const REQUIREMENT_WARNING
= 1;
22 * Requirement severity -- Error condition; abort installation.
24 const REQUIREMENT_ERROR
= 2;
26 protected $system_checks = array(
28 'checkServerVariables',
29 'checkMysqlConnectExists',
30 'checkJsonEncodeExists',
33 protected $database_checks = array(
34 'checkMysqlConnection',
37 'checkMysqlTempTables',
38 'checkMySQLAutoIncrementIncrementOne',
40 'checkMysqlThreadStack',
41 'checkMysqlLockTables',
45 * Run all requirements tests.
47 * @param array $config
48 * An array with two keys:
52 * @return array An array of check summaries. Each array contains the keys 'title', 'severity', and 'details'.
54 public function checkAll(array $config) {
55 return array_merge($this->checkSystem($config['file_paths']), $this->checkDatabase($config['db_config']));
59 * Check system requirements are met, such as sufficient memory,
60 * necessary file paths are writable and required php extensions
63 * @param array $file_paths
64 * An array of file paths that will be checked to confirm they
69 public function checkSystem(array $file_paths) {
72 $errors[] = $this->checkFilepathIsWritable($file_paths);
73 foreach ($this->system_checks
as $check) {
74 $errors[] = $this->$check();
81 * Check database connection, database version and other
82 * database requirements are met.
84 * @param array $db_config
86 * - host (with optional port specified eg. localhost:12345)
87 * = database (name of database to select)
93 public function checkDatabase(array $db_config) {
96 foreach ($this->database_checks
as $check) {
97 $errors[] = $this->$check($db_config);
104 * Check configured php Memory
107 public function checkMemory() {
108 $min = 1024 * 1024 * 32;
109 $recommended = 1024 * 1024 * 64;
111 $mem = $this->getPHPMemory();
112 $mem_string = ini_get('memory_limit');
115 'title' => 'CiviCRM memory check',
116 'severity' => $this::REQUIREMENT_OK
,
117 'details' => "You have $mem_string allocated (minimum 32Mb, recommended 64Mb)",
120 if ($mem < $min && $mem > 0) {
121 $results['severity'] = $this::REQUIREMENT_ERROR
;
123 else if ($mem < $recommended && $mem != 0) {
124 $results['severity'] = $this::REQUIREMENT_WARNING
;
126 else if ($mem == 0) {
127 $results['details'] = "Cannot determine PHP memory allocation. Install only if you're sure you've allocated at least 32 MB.";
128 $results['severity'] = $this::REQUIREMENT_WARNING
;
135 * Get Configured PHP memory
138 protected function getPHPMemory() {
139 $memString = ini_get("memory_limit");
141 switch (strtolower(substr($memString, -1))) {
143 return round(substr($memString, 0, -1) * 1024);
145 return round(substr($memString, 0, -1) * 1024 * 1024);
147 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
149 return round($memString);
156 function checkServerVariables() {
158 'title' => 'CiviCRM PHP server variables',
159 'severity' => $this::REQUIREMENT_OK
,
160 'details' => 'The required $_SERVER variables are set',
163 $required_variables = array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME');
166 foreach ($required_variables as $required_variable) {
167 if (empty($_SERVER[$required_variable])) {
168 $missing[] = '$_SERVER[' . $required_variable . ']';
173 $results['severity'] = $this::REQUIREMENT_ERROR
;
174 $results['details'] = 'The following PHP variables are not set: ' . implode(', ', $missing);
183 public function checkJsonEncodeExists() {
185 'title' => 'CiviCRM JSON encoding support',
186 'severity' => $this::REQUIREMENT_OK
,
187 'details' => 'Function json_encode() found',
189 if (!function_exists('json_encode')) {
190 $results['severity'] = $this::REQUIREMENT_ERROR
;
191 $results['details'] = 'Function json_encode() does not exist';
200 public function checkMysqlConnectExists() {
202 'title' => 'CiviCRM MySQL check',
203 'severity' => $this::REQUIREMENT_OK
,
204 'details' => 'Function mysql_connect() found',
206 if (!function_exists('mysql_connect')) {
207 $results['severity'] = $this::REQUIREMENT_ERROR
;
208 $results['details'] = 'Function mysql_connect() does not exist';
215 * @param array $db_config
219 public function checkMysqlConnection(array $db_config) {
221 'title' => 'CiviCRM MySQL connection',
222 'severity' => $this::REQUIREMENT_OK
,
223 'details' => "Connected",
226 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
229 $results['details'] = mysql_error();
230 $results['severity'] = $this::REQUIREMENT_ERROR
;
234 if (!@mysql_select_db
($db_config['database'], $conn)) {
235 $results['details'] = mysql_error();
236 $results['severity'] = $this::REQUIREMENT_ERROR
;
244 * @param array $db_config
248 public function checkMysqlVersion(array $db_config) {
251 'title' => 'CiviCRM MySQL Version',
252 'severity' => $this::REQUIREMENT_OK
,
255 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
256 if (!$conn ||
!($info = mysql_get_server_info($conn))) {
257 $results['severity'] = $this::REQUIREMENT_WARNING
;
258 $results['details'] = "Cannot determine the version of MySQL installed. Please ensure at least version {$min} is installed.";
262 if (version_compare($info, $min) == -1) {
263 $results['severity'] = $this::REQUIREMENT_ERROR
;
264 $results['details'] = "MySQL version is {$info}; minimum required is {$min}";
268 $results['details'] = "MySQL version is {$info}";
273 * @param array $db_config
277 public function checkMysqlInnodb(array $db_config) {
279 'title' => 'CiviCRM InnoDB support',
280 'severity' => $this::REQUIREMENT_ERROR
,
281 'details' => 'Could not determine if MySQL has InnoDB support. Assuming none.'
284 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
289 $innodb_support = FALSE;
290 $result = mysql_query("SHOW ENGINES", $conn);
291 while ($values = mysql_fetch_array($result)) {
292 if ($values['Engine'] == 'InnoDB') {
293 if (strtolower($values['Support']) == 'yes' ||
strtolower($values['Support']) == 'default') {
294 $innodb_support = TRUE;
300 if ($innodb_support) {
301 $results['severity'] = $this::REQUIREMENT_OK
;
302 $results['details'] = 'MySQL supports InnoDB';
308 * @param array $db_config
312 public function checkMysqlTempTables(array $db_config) {
314 'title' => 'CiviCRM MySQL Temp Tables',
315 'severity' => $this::REQUIREMENT_OK
,
316 'details' => 'MySQL server supports temporary tables',
319 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
321 $results['severity'] = $this::REQUIREMENT_ERROR
;
322 $results['details'] = "Could not connect to database";
326 if (!@mysql_select_db
($db_config['database'], $conn)) {
327 $results['severity'] = $this::REQUIREMENT_ERROR
;
328 $results['details'] = "Could not select the database";
332 $r = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
334 $results['severity'] = $this::REQUIREMENT_ERROR
;
335 $results['details'] = "Database does not support creation of temporary tables";
339 mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
348 public function checkMysqlTrigger($db_config) {
350 'title' => 'CiviCRM MySQL Trigger',
351 'severity' => $this::REQUIREMENT_OK
,
352 'details' => 'Database supports MySQL triggers',
355 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
357 $results['severity'] = $this::REQUIREMENT_ERROR
;
358 $results['details'] = 'Could not connect to database';
362 if (!@mysql_select_db
($db_config['database'], $conn)) {
363 $results['severity'] = $this::REQUIREMENT_ERROR
;
364 $results['details'] = "Could not select the database";
368 $r = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
370 $results['severity'] = $this::REQUIREMENT_ERROR
;
371 $results['details'] = 'Could not create a table to run test';
375 $r = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
377 $results['severity'] = $this::REQUIREMENT_ERROR
;
378 $results['details'] = 'Database does not support creation of triggers';
381 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
384 mysql_query('DROP TABLE civicrm_install_temp_table_test');
389 * @param array $db_config
393 public function checkMySQLAutoIncrementIncrementOne(array $db_config) {
395 'title' => 'CiviCRM MySQL AutoIncrementIncrement',
396 'severity' => $this::REQUIREMENT_OK
,
397 'details' => 'MySQL server auto_increment_increment is 1',
400 $conn = @mysql_connect
($db_config['host'], $db_config['username'], $db_config['password']);
402 $results['severity'] = $this::REQUIREMENT_ERROR
;
403 $results['details'] = 'Could not connect to database';
407 $r = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
409 $results['severity'] = $this::REQUIREMENT_ERROR
;
410 $results['details'] = 'Could not query database server variables';
414 $values = mysql_fetch_row($r);
415 if ($values[1] != 1) {
416 $results['severity'] = $this::REQUIREMENT_ERROR
;
417 $results['details'] = 'MySQL server auto_increment_increment is not 1';
427 public function checkMysqlThreadStack($db_config) {
428 $min_thread_stack = 192;
431 'title' => 'CiviCRM Mysql thread stack',
432 'severity' => $this::REQUIREMENT_OK
,
433 'details' => 'MySQL thread_stack is OK',
436 $conn = @mysql_connect
($db_config['server'], $db_config['username'], $db_config['password']);
438 $results['severity'] = $this::REQUIREMENT_ERROR
;
439 $results['details'] = 'Could not connect to database';
443 if (!@mysql_select_db
($db_config['database'], $conn)) {
444 $results['severity'] = $this::REQUIREMENT_ERROR
;
445 $results['details'] = 'Could not select the database';
449 $r = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
451 $results['severity'] = $this::REQUIREMENT_ERROR
;
452 $results['details'] = 'Could not query thread_stack value';
455 $values = mysql_fetch_row($r);
456 if ($values[1] < (1024 * $min_thread_stack)) {
457 $results['severity'] = $this::REQUIREMENT_ERROR
;
458 $results['details'] = 'MySQL thread_stack is ' . ($values[1] / 1024) . "kb (minimum required is {$min_thread_stack} kb";
470 function checkMysqlLockTables($db_config) {
472 'title' => 'CiviCRM MySQL Lock Tables',
473 'severity' => $this::REQUIREMENT_OK
,
474 'details' => 'Can successfully lock and unlock tables',
477 $conn = @mysql_connect
($db_config['server'], $db_config['username'], $db_config['password']);
479 $results['severity'] = $this::REQUIREMENT_ERROR
;
480 $results['details'] = 'Could not connect to database';
484 if (!@mysql_select_db
($db_config['database'], $conn)) {
485 $results['severity'] = $this::REQUIREMENT_ERROR
;
486 $results['details'] = 'Could not select the database';
491 $r = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
493 $results['severity'] = $this::REQUIREMENT_ERROR
;
494 $results['details'] = 'Could not create a table';
499 $r = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
501 $results['severity'] = $this::REQUIREMENT_ERROR
;
502 $results['details'] = 'Could not obtain a write lock';
507 $r = mysql_query('UNLOCK TABLES', $conn);
509 $results['severity'] = $this::REQUIREMENT_ERROR
;
510 $results['details'] = 'Could not release table lock';
522 public function checkFilepathIsWritable($file_paths) {
524 'title' => 'CiviCRM directories are writable',
525 'severity' => $this::REQUIREMENT_OK
,
526 'details' => 'All required directories are writable: ' . implode(', ', $file_paths),
529 $unwritable_dirs = array();
530 foreach ($file_paths as $path) {
531 if (!is_writable($path)) {
532 $unwritable_dirs[] = $path;
536 if ($unwritable_dirs) {
537 $results['severity'] = $this::REQUIREMENT_ERROR
;
538 $results['details'] = "The following directories need to be made writable by the webserver: " . implode(', ', $unwritable_dirs);