commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / Civi / Install / Requirements.php
1 <?php
2
3 namespace Civi\Install;
4
5 /**
6 * Class Requirements
7 * @package Civi\Install
8 */
9 class 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
26 protected $system_checks = array(
27 'checkMemory',
28 'checkServerVariables',
29 'checkMysqlConnectExists',
30 'checkJsonEncodeExists',
31 );
32
33 protected $database_checks = array(
34 'checkMysqlConnection',
35 'checkMysqlVersion',
36 'checkMysqlInnodb',
37 'checkMysqlTempTables',
38 'checkMySQLAutoIncrementIncrementOne',
39 'checkMysqlTrigger',
40 'checkMysqlThreadStack',
41 'checkMysqlLockTables',
42 );
43
44 /**
45 * Run all requirements tests.
46 *
47 * @param array $config
48 * An array with two keys:
49 * - file_paths
50 * - db_config
51 *
52 * @return array
53 * An array of check summaries. Each array contains the keys 'title', 'severity', and 'details'.
54 */
55 public function checkAll(array $config) {
56 return array_merge($this->checkSystem($config['file_paths']), $this->checkDatabase($config['db_config']));
57 }
58
59 /**
60 * Check system requirements are met, such as sufficient memory,
61 * necessary file paths are writable and required php extensions
62 * are available.
63 *
64 * @param array $file_paths
65 * An array of file paths that will be checked to confirm they
66 * are writable.
67 *
68 * @return array
69 */
70 public function checkSystem(array $file_paths) {
71 $errors = array();
72
73 $errors[] = $this->checkFilepathIsWritable($file_paths);
74 foreach ($this->system_checks as $check) {
75 $errors[] = $this->$check();
76 }
77
78 return $errors;
79 }
80
81 /**
82 * Check database connection, database version and other
83 * database requirements are met.
84 *
85 * @param array $db_config
86 * An array with keys:
87 * - host (with optional port specified eg. localhost:12345)
88 * - database (name of database to select)
89 * - username
90 * - password
91 *
92 * @return array
93 */
94 public function checkDatabase(array $db_config) {
95 $errors = array();
96
97 foreach ($this->database_checks as $check) {
98 $errors[] = $this->$check($db_config);
99 }
100
101 return $errors;
102 }
103
104 /**
105 * Check configured php Memory.
106 * @return array
107 */
108 public function checkMemory() {
109 $min = 1024 * 1024 * 32;
110 $recommended = 1024 * 1024 * 64;
111
112 $mem = $this->getPHPMemory();
113 $mem_string = ini_get('memory_limit');
114
115 $results = array(
116 'title' => 'CiviCRM memory check',
117 'severity' => $this::REQUIREMENT_OK,
118 'details' => "You have $mem_string allocated (minimum 32Mb, recommended 64Mb)",
119 );
120
121 if ($mem < $min && $mem > 0) {
122 $results['severity'] = $this::REQUIREMENT_ERROR;
123 }
124 elseif ($mem < $recommended && $mem != 0) {
125 $results['severity'] = $this::REQUIREMENT_WARNING;
126 }
127 elseif ($mem == 0) {
128 $results['details'] = "Cannot determine PHP memory allocation. Install only if you're sure you've allocated at least 32 MB.";
129 $results['severity'] = $this::REQUIREMENT_WARNING;
130 }
131
132 return $results;
133 }
134
135 /**
136 * Get Configured PHP memory.
137 * @return float
138 */
139 protected function getPHPMemory() {
140 $memString = ini_get("memory_limit");
141
142 switch (strtolower(substr($memString, -1))) {
143 case "k":
144 return round(substr($memString, 0, -1) * 1024);
145
146 case "m":
147 return round(substr($memString, 0, -1) * 1024 * 1024);
148
149 case "g":
150 return round(substr($memString, 0, -1) * 1024 * 1024 * 1024);
151
152 default:
153 return round($memString);
154 }
155 }
156
157 /**
158 * @return array
159 */
160 public function checkServerVariables() {
161 $results = array(
162 'title' => 'CiviCRM PHP server variables',
163 'severity' => $this::REQUIREMENT_OK,
164 'details' => 'The required $_SERVER variables are set',
165 );
166
167 $required_variables = array('SCRIPT_NAME', 'HTTP_HOST', 'SCRIPT_FILENAME');
168 $missing = array();
169
170 foreach ($required_variables as $required_variable) {
171 if (empty($_SERVER[$required_variable])) {
172 $missing[] = '$_SERVER[' . $required_variable . ']';
173 }
174 }
175
176 if ($missing) {
177 $results['severity'] = $this::REQUIREMENT_ERROR;
178 $results['details'] = 'The following PHP variables are not set: ' . implode(', ', $missing);
179 }
180
181 return $results;
182 }
183
184 /**
185 * @return array
186 */
187 public function checkJsonEncodeExists() {
188 $results = array(
189 'title' => 'CiviCRM JSON encoding support',
190 'severity' => $this::REQUIREMENT_OK,
191 'details' => 'Function json_encode() found',
192 );
193 if (!function_exists('json_encode')) {
194 $results['severity'] = $this::REQUIREMENT_ERROR;
195 $results['details'] = 'Function json_encode() does not exist';
196 }
197
198 return $results;
199 }
200
201 /**
202 * @return array
203 */
204 public function checkMysqlConnectExists() {
205 $results = array(
206 'title' => 'CiviCRM MySQL check',
207 'severity' => $this::REQUIREMENT_OK,
208 'details' => 'Function mysql_connect() found',
209 );
210 if (!function_exists('mysql_connect')) {
211 $results['severity'] = $this::REQUIREMENT_ERROR;
212 $results['details'] = 'Function mysql_connect() does not exist';
213 }
214
215 return $results;
216 }
217
218 /**
219 * @param array $db_config
220 *
221 * @return array
222 */
223 public function checkMysqlConnection(array $db_config) {
224 $results = array(
225 'title' => 'CiviCRM MySQL connection',
226 'severity' => $this::REQUIREMENT_OK,
227 'details' => "Connected",
228 );
229
230 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
231
232 if (!$conn) {
233 $results['details'] = mysql_error();
234 $results['severity'] = $this::REQUIREMENT_ERROR;
235 return $results;
236 }
237
238 if (!@mysql_select_db($db_config['database'], $conn)) {
239 $results['details'] = mysql_error();
240 $results['severity'] = $this::REQUIREMENT_ERROR;
241 return $results;
242 }
243
244 return $results;
245 }
246
247 /**
248 * @param array $db_config
249 *
250 * @return array
251 */
252 public function checkMysqlVersion(array $db_config) {
253 $min = '5.1';
254 $results = array(
255 'title' => 'CiviCRM MySQL Version',
256 'severity' => $this::REQUIREMENT_OK,
257 );
258
259 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
260 if (!$conn || !($info = mysql_get_server_info($conn))) {
261 $results['severity'] = $this::REQUIREMENT_WARNING;
262 $results['details'] = "Cannot determine the version of MySQL installed. Please ensure at least version {$min} is installed.";
263 return $results;
264 }
265
266 if (version_compare($info, $min) == -1) {
267 $results['severity'] = $this::REQUIREMENT_ERROR;
268 $results['details'] = "MySQL version is {$info}; minimum required is {$min}";
269 return $results;
270 }
271
272 $results['details'] = "MySQL version is {$info}";
273 return $results;
274 }
275
276 /**
277 * @param array $db_config
278 *
279 * @return array
280 */
281 public function checkMysqlInnodb(array $db_config) {
282 $results = array(
283 'title' => 'CiviCRM InnoDB support',
284 'severity' => $this::REQUIREMENT_ERROR,
285 'details' => 'Could not determine if MySQL has InnoDB support. Assuming none.',
286 );
287
288 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
289 if (!$conn) {
290 return $results;
291 }
292
293 $innodb_support = FALSE;
294 $result = mysql_query("SHOW ENGINES", $conn);
295 while ($values = mysql_fetch_array($result)) {
296 if ($values['Engine'] == 'InnoDB') {
297 if (strtolower($values['Support']) == 'yes' || strtolower($values['Support']) == 'default') {
298 $innodb_support = TRUE;
299 break;
300 }
301 }
302 }
303
304 if ($innodb_support) {
305 $results['severity'] = $this::REQUIREMENT_OK;
306 $results['details'] = 'MySQL supports InnoDB';
307 }
308 return $results;
309 }
310
311 /**
312 * @param array $db_config
313 *
314 * @return array
315 */
316 public function checkMysqlTempTables(array $db_config) {
317 $results = array(
318 'title' => 'CiviCRM MySQL Temp Tables',
319 'severity' => $this::REQUIREMENT_OK,
320 'details' => 'MySQL server supports temporary tables',
321 );
322
323 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
324 if (!$conn) {
325 $results['severity'] = $this::REQUIREMENT_ERROR;
326 $results['details'] = "Could not connect to database";
327 return $results;
328 }
329
330 if (!@mysql_select_db($db_config['database'], $conn)) {
331 $results['severity'] = $this::REQUIREMENT_ERROR;
332 $results['details'] = "Could not select the database";
333 return $results;
334 }
335
336 $r = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
337 if (!$r) {
338 $results['severity'] = $this::REQUIREMENT_ERROR;
339 $results['details'] = "Database does not support creation of temporary tables";
340 return $results;
341 }
342
343 mysql_query('DROP TEMPORARY TABLE civicrm_install_temp_table_test');
344 return $results;
345 }
346
347 /**
348 * @param $db_config
349 *
350 * @return array
351 */
352 public function checkMysqlTrigger($db_config) {
353 $results = array(
354 'title' => 'CiviCRM MySQL Trigger',
355 'severity' => $this::REQUIREMENT_OK,
356 'details' => 'Database supports MySQL triggers',
357 );
358
359 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
360 if (!$conn) {
361 $results['severity'] = $this::REQUIREMENT_ERROR;
362 $results['details'] = 'Could not connect to database';
363 return $results;
364 }
365
366 if (!@mysql_select_db($db_config['database'], $conn)) {
367 $results['severity'] = $this::REQUIREMENT_ERROR;
368 $results['details'] = "Could not select the database";
369 return $results;
370 }
371
372 $r = mysql_query('CREATE TABLE civicrm_install_temp_table_test (test text)', $conn);
373 if (!$r) {
374 $results['severity'] = $this::REQUIREMENT_ERROR;
375 $results['details'] = 'Could not create a table to run test';
376 return $results;
377 }
378
379 $r = mysql_query('CREATE TRIGGER civicrm_install_temp_table_test_trigger BEFORE INSERT ON civicrm_install_temp_table_test FOR EACH ROW BEGIN END');
380 if (!$r) {
381 $results['severity'] = $this::REQUIREMENT_ERROR;
382 $results['details'] = 'Database does not support creation of triggers';
383 }
384 else {
385 mysql_query('DROP TRIGGER civicrm_install_temp_table_test_trigger');
386 }
387
388 mysql_query('DROP TABLE civicrm_install_temp_table_test');
389 return $results;
390 }
391
392 /**
393 * @param array $db_config
394 *
395 * @return array
396 */
397 public function checkMySQLAutoIncrementIncrementOne(array $db_config) {
398 $results = array(
399 'title' => 'CiviCRM MySQL AutoIncrementIncrement',
400 'severity' => $this::REQUIREMENT_OK,
401 'details' => 'MySQL server auto_increment_increment is 1',
402 );
403
404 $conn = @mysql_connect($db_config['host'], $db_config['username'], $db_config['password']);
405 if (!$conn) {
406 $results['severity'] = $this::REQUIREMENT_ERROR;
407 $results['details'] = 'Could not connect to database';
408 return $results;
409 }
410
411 $r = mysql_query("SHOW variables like 'auto_increment_increment'", $conn);
412 if (!$r) {
413 $results['severity'] = $this::REQUIREMENT_ERROR;
414 $results['details'] = 'Could not query database server variables';
415 return $results;
416 }
417
418 $values = mysql_fetch_row($r);
419 if ($values[1] != 1) {
420 $results['severity'] = $this::REQUIREMENT_ERROR;
421 $results['details'] = 'MySQL server auto_increment_increment is not 1';
422 }
423 return $results;
424 }
425
426 /**
427 * @param $db_config
428 *
429 * @return array
430 */
431 public function checkMysqlThreadStack($db_config) {
432 $min_thread_stack = 192;
433
434 $results = array(
435 'title' => 'CiviCRM Mysql thread stack',
436 'severity' => $this::REQUIREMENT_OK,
437 'details' => 'MySQL thread_stack is OK',
438 );
439
440 $conn = @mysql_connect($db_config['server'], $db_config['username'], $db_config['password']);
441 if (!$conn) {
442 $results['severity'] = $this::REQUIREMENT_ERROR;
443 $results['details'] = 'Could not connect to database';
444 return $results;
445 }
446
447 if (!@mysql_select_db($db_config['database'], $conn)) {
448 $results['severity'] = $this::REQUIREMENT_ERROR;
449 $results['details'] = 'Could not select the database';
450 return $results;
451 }
452
453 $r = mysql_query("SHOW VARIABLES LIKE 'thread_stack'", $conn); // bytes => kb
454 if (!$r) {
455 $results['severity'] = $this::REQUIREMENT_ERROR;
456 $results['details'] = 'Could not query thread_stack value';
457 }
458 else {
459 $values = mysql_fetch_row($r);
460 if ($values[1] < (1024 * $min_thread_stack)) {
461 $results['severity'] = $this::REQUIREMENT_ERROR;
462 $results['details'] = 'MySQL thread_stack is ' . ($values[1] / 1024) . "kb (minimum required is {$min_thread_stack} kb";
463 }
464 }
465
466 return $results;
467 }
468
469 /**
470 * @param $db_config
471 *
472 * @return array
473 */
474 public function checkMysqlLockTables($db_config) {
475 $results = array(
476 'title' => 'CiviCRM MySQL Lock Tables',
477 'severity' => $this::REQUIREMENT_OK,
478 'details' => 'Can successfully lock and unlock tables',
479 );
480
481 $conn = @mysql_connect($db_config['server'], $db_config['username'], $db_config['password']);
482 if (!$conn) {
483 $results['severity'] = $this::REQUIREMENT_ERROR;
484 $results['details'] = 'Could not connect to database';
485 return $results;
486 }
487
488 if (!@mysql_select_db($db_config['database'], $conn)) {
489 $results['severity'] = $this::REQUIREMENT_ERROR;
490 $results['details'] = 'Could not select the database';
491 mysql_close($conn);
492 return $results;
493 }
494
495 $r = mysql_query('CREATE TEMPORARY TABLE civicrm_install_temp_table_test (test text)', $conn);
496 if (!$r) {
497 $results['severity'] = $this::REQUIREMENT_ERROR;
498 $results['details'] = 'Could not create a table';
499 mysql_close($conn);
500 return $results;
501 }
502
503 $r = mysql_query('LOCK TABLES civicrm_install_temp_table_test WRITE', $conn);
504 if (!$r) {
505 $results['severity'] = $this::REQUIREMENT_ERROR;
506 $results['details'] = 'Could not obtain a write lock';
507 mysql_close($conn);
508 return $results;
509 }
510
511 $r = mysql_query('UNLOCK TABLES', $conn);
512 if (!$r) {
513 $results['severity'] = $this::REQUIREMENT_ERROR;
514 $results['details'] = 'Could not release table lock';
515 }
516
517 mysql_close($conn);
518 return $results;
519 }
520
521 /**
522 * @param $file_paths
523 *
524 * @return array
525 */
526 public function checkFilepathIsWritable($file_paths) {
527 $results = array(
528 'title' => 'CiviCRM directories are writable',
529 'severity' => $this::REQUIREMENT_OK,
530 'details' => 'All required directories are writable: ' . implode(', ', $file_paths),
531 );
532
533 $unwritable_dirs = array();
534 foreach ($file_paths as $path) {
535 if (!is_writable($path)) {
536 $unwritable_dirs[] = $path;
537 }
538 }
539
540 if ($unwritable_dirs) {
541 $results['severity'] = $this::REQUIREMENT_ERROR;
542 $results['details'] = "The following directories need to be made writable by the webserver: " . implode(', ', $unwritable_dirs);
543 }
544
545 return $results;
546 }
547
548 }