Merge pull request #11751 from JMAConsulting/CRM-21806
[civicrm-core.git] / CRM / Utils / Check / Component / Env.php
CommitLineData
1e927c45
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
1e927c45 5 +--------------------------------------------------------------------+
8c9251b3 6 | Copyright CiviCRM LLC (c) 2004-2018 |
1e927c45
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
1e927c45
TO
27
28/**
29 *
30 * @package CRM
8c9251b3 31 * @copyright CiviCRM LLC (c) 2004-2018
1e927c45 32 */
3a0d0bbd 33class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
1e927c45 34
31e80d5a
CW
35 /**
36 * @return array
37 */
38 public function checkPhpVersion() {
39 $messages = array();
cc1f4988 40 $phpVersion = phpversion();
31e80d5a 41
cc1f4988 42 if (version_compare($phpVersion, CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER) >= 0) {
31e80d5a 43 $messages[] = new CRM_Utils_Check_Message(
165aab59 44 __FUNCTION__,
cc1f4988 45 ts('This system uses PHP version %1 which meets or exceeds the recommendation of %2.',
d0c1e96f 46 array(
cc1f4988
CW
47 1 => $phpVersion,
48 2 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
d0c1e96f
TO
49 )),
50 ts('PHP Up-to-Date'),
51 \Psr\Log\LogLevel::INFO,
52 'fa-server'
53 );
54 }
cc1f4988 55 elseif (version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER) >= 0) {
d0c1e96f
TO
56 $messages[] = new CRM_Utils_Check_Message(
57 __FUNCTION__,
cc1f4988 58 ts('This system uses PHP version %1. This meets the minimum recommendations and you do not need to upgrade immediately, but the preferred version is %2.',
31e80d5a 59 array(
cc1f4988
CW
60 1 => $phpVersion,
61 2 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
31e80d5a
CW
62 )),
63 ts('PHP Out-of-Date'),
165aab59
CW
64 \Psr\Log\LogLevel::NOTICE,
65 'fa-server'
31e80d5a
CW
66 );
67 }
cc1f4988 68 elseif (version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER) >= 0) {
31e80d5a 69 $messages[] = new CRM_Utils_Check_Message(
165aab59 70 __FUNCTION__,
cc1f4988 71 ts('This system uses PHP version %1. This meets the minimum requirements for CiviCRM to function but is not recommended. At least PHP version %2 is recommended; the preferrred version is %3.',
31e80d5a 72 array(
cc1f4988
CW
73 1 => $phpVersion,
74 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
75 3 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
31e80d5a 76 )),
d0c1e96f
TO
77 ts('PHP Out-of-Date'),
78 \Psr\Log\LogLevel::WARNING,
165aab59 79 'fa-server'
31e80d5a
CW
80 );
81 }
cc1f4988
CW
82 else {
83 $messages[] = new CRM_Utils_Check_Message(
84 __FUNCTION__,
85 ts('This system uses PHP version %1. To ensure the continued operation of CiviCRM, upgrade your server now. At least PHP version %2 is recommended; the preferrred version is %3.',
86 array(
87 1 => $phpVersion,
88 2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
89 3 => CRM_Upgrade_Incremental_General::RECOMMENDED_PHP_VER,
90 )),
91 ts('PHP Out-of-Date'),
92 \Psr\Log\LogLevel::ERROR,
93 'fa-server'
94 );
95 }
31e80d5a
CW
96
97 return $messages;
98 }
99
991298ee
TO
100 /**
101 * @return array
102 */
103 public function checkPhpMysqli() {
104 $messages = array();
105
106 if (!extension_loaded('mysqli')) {
107 $messages[] = new CRM_Utils_Check_Message(
108 __FUNCTION__,
109 ts('Future versions of CiviCRM may require the PHP extension "%2". To ensure that your system will be compatible, please install it in advance. For more explanation, see <a href="%1">the announcement</a>.',
110 array(
111 1 => 'https://civicrm.org/blog/totten/psa-please-verify-php-extension-mysqli',
112 2 => 'mysqli',
113 )),
114 ts('Forward Compatibility: Enable "mysqli"'),
115 \Psr\Log\LogLevel::WARNING,
116 'fa-server'
117 );
118 }
119
120 return $messages;
121 }
122
7342d7c4
TO
123 /**
124 * Check that the MySQL time settings match the PHP time settings.
125 *
126 * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings
127 */
1e927c45 128 public function checkMysqlTime() {
f3cfdce3
J
129 //CRM-19115 - Always set MySQL time before checking it.
130 CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
1e927c45
TO
131 $messages = array();
132
133 $phpNow = date('Y-m-d H:i');
134 $sqlNow = CRM_Core_DAO::singleValueQuery("SELECT date_format(now(), '%Y-%m-%d %H:%i')");
8010540a 135 if (!CRM_Utils_Time::isEqual($phpNow, $sqlNow, 2.5 * 60)) {
1e927c45 136 $messages[] = new CRM_Utils_Check_Message(
165aab59 137 __FUNCTION__,
1e927c45 138 ts('Timestamps reported by MySQL (eg "%2") and PHP (eg "%3" ) are mismatched.<br /><a href="%1">Read more about this warning</a>', array(
7342d7c4 139 1 => CRM_Utils_System::getWikiBaseURL() . 'checkMysqlTime',
1e927c45
TO
140 2 => $sqlNow,
141 3 => $phpNow,
142 )),
1b366958 143 ts('Timestamp Mismatch'),
165aab59
CW
144 \Psr\Log\LogLevel::ERROR,
145 'fa-server'
1e927c45
TO
146 );
147 }
148
149 return $messages;
150 }
7342d7c4 151
5bc392e6
EM
152 /**
153 * @return array
154 */
7342d7c4 155 public function checkDebug() {
7342d7c4
TO
156 $config = CRM_Core_Config::singleton();
157 if ($config->debug) {
4b540f18 158 $message = new CRM_Utils_Check_Message(
165aab59 159 __FUNCTION__,
7342d7c4
TO
160 ts('Warning: Debug is enabled in <a href="%1">system settings</a>. This should not be enabled on production servers.',
161 array(1 => CRM_Utils_System::url('civicrm/admin/setting/debug', 'reset=1'))),
1b366958 162 ts('Debug Mode Enabled'),
165aab59
CW
163 \Psr\Log\LogLevel::WARNING,
164 'fa-bug'
7342d7c4 165 );
4b540f18
CW
166 $message->addAction(
167 ts('Disable Debug Mode'),
168 ts('Disable debug mode now?'),
169 'api3',
170 array('Setting', 'create', array('debug_enabled' => 0))
171 );
172 return array($message);
7342d7c4
TO
173 }
174
4b540f18 175 return array();
7342d7c4
TO
176 }
177
5bc392e6
EM
178 /**
179 * @return array
180 */
7342d7c4
TO
181 public function checkOutboundMail() {
182 $messages = array();
183
aaffa79f 184 $mailingInfo = Civi::settings()->get('mailing_backend');
7342d7c4
TO
185 if (($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB
186 || (defined('CIVICRM_MAIL_LOG') && CIVICRM_MAIL_LOG)
187 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED
188 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MOCK)
189 ) {
190 $messages[] = new CRM_Utils_Check_Message(
165aab59 191 __FUNCTION__,
7342d7c4
TO
192 ts('Warning: Outbound email is disabled in <a href="%1">system settings</a>. Proper settings should be enabled on production servers.',
193 array(1 => CRM_Utils_System::url('civicrm/admin/setting/smtp', 'reset=1'))),
1b366958 194 ts('Outbound Email Disabled'),
165aab59
CW
195 \Psr\Log\LogLevel::WARNING,
196 'fa-envelope'
7342d7c4
TO
197 );
198 }
199
200 return $messages;
201 }
96025800 202
1b366958
AH
203 /**
204 * Check that domain email and org name are set
205 * @return array
206 */
1b366958
AH
207 public function checkDomainNameEmail() {
208 $messages = array();
209
210 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(TRUE);
211 $domain = CRM_Core_BAO_Domain::getDomain();
212 $domainName = $domain->name;
213 $fixEmailUrl = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1");
214
215 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
216 if (!$domainName || $domainName == 'Default Domain Name') {
217 $msg = ts("Please enter your organization's <a href=\"%1\">name, primary address, and default FROM Email Address</a> (for system-generated emails).",
218 array(1 => $fixEmailUrl));
219 }
220 else {
221 $msg = ts('Please enter a <a href="%1">default FROM Email Address</a> (for system-generated emails).',
222 array(1 => $fixEmailUrl));
223 }
224 }
225 elseif (!$domainName || $domainName == 'Default Domain Name') {
226 $msg = ts("Please enter your organization's <a href=\"%1\">name and primary address</a>.",
227 array(1 => $fixEmailUrl));
228 }
aacaa119
AH
229
230 if (!empty($msg)) {
231 $messages[] = new CRM_Utils_Check_Message(
165aab59 232 __FUNCTION__,
aacaa119
AH
233 $msg,
234 ts('Complete Setup'),
165aab59
CW
235 \Psr\Log\LogLevel::WARNING,
236 'fa-check-square-o'
aacaa119
AH
237 );
238 }
1b366958
AH
239
240 return $messages;
241 }
242
243 /**
244 * Checks if a default bounce handling mailbox is set up
245 * @return array
246 */
1b366958
AH
247 public function checkDefaultMailbox() {
248 $messages = array();
249 $config = CRM_Core_Config::singleton();
250
251 if (in_array('CiviMail', $config->enableComponents) &&
252 CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG"
253 ) {
254 $message = new CRM_Utils_Check_Message(
165aab59 255 __FUNCTION__,
aa96ce62 256 ts('Please configure a <a href="%1">default mailbox</a> for CiviMail.',
1b366958
AH
257 array(1 => CRM_Utils_System::url('civicrm/admin/mailSettings', "reset=1"))),
258 ts('Configure Default Mailbox'),
165aab59
CW
259 \Psr\Log\LogLevel::WARNING,
260 'fa-envelope'
1b366958 261 );
2a243675
CW
262 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('page' => 'user/advanced-configuration/email-system-configuration/', 'URLonly' => TRUE)) . '""';
263 $message->addHelp(
264 ts('A default mailbox must be configured for email bounce processing.') . '<br />' .
265 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
266 );
1b366958
AH
267 $messages[] = $message;
268 }
269
270 return $messages;
271 }
aa96ce62
AH
272
273 /**
274 * Checks if cron has run in a reasonable amount of time
275 * @return array
276 */
aa96ce62
AH
277 public function checkLastCron() {
278 $messages = array();
279
280 $statusPreference = new CRM_Core_DAO_StatusPreference();
281 $statusPreference->domain_id = CRM_Core_Config::domainID();
282 $statusPreference->name = 'checkLastCron';
283
0296367d
CW
284 if ($statusPreference->find(TRUE) && !empty($statusPreference->check_info)) {
285 $lastCron = $statusPreference->check_info;
fba5f6ac
AH
286 $msg = ts('Last cron run at %1.', array(1 => CRM_Utils_Date::customFormat(date('c', $lastCron))));
287 }
288 else {
289 $lastCron = 0;
290 $msg = ts('No cron runs have been recorded.');
291 }
aa96ce62 292
aa96ce62
AH
293 if ($lastCron > gmdate('U') - 3600) {
294 $messages[] = new CRM_Utils_Check_Message(
165aab59 295 __FUNCTION__,
aa96ce62
AH
296 $msg,
297 ts('Cron Running OK'),
165aab59
CW
298 \Psr\Log\LogLevel::INFO,
299 'fa-clock-o'
aa96ce62
AH
300 );
301 }
fba5f6ac 302 else {
aa96ce62 303 $message = new CRM_Utils_Check_Message(
165aab59 304 __FUNCTION__,
aa96ce62
AH
305 $msg,
306 ts('Cron Not Running'),
2a243675 307 ($lastCron > gmdate('U') - 86400) ? \Psr\Log\LogLevel::WARNING : \Psr\Log\LogLevel::ERROR,
165aab59 308 'fa-clock-o'
aa96ce62 309 );
2a243675
CW
310 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('resource' => 'wiki', 'page' => 'Managing Scheduled Jobs', 'URLonly' => TRUE)) . '""';
311 $message->addHelp(
312 ts('Configuring cron on your server is necessary for running scheduled jobs such as sending mail and scheduled reminders.') . '<br />' .
313 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
314 );
aa96ce62
AH
315 $messages[] = $message;
316 }
317
318 return $messages;
319 }
fba5f6ac 320
50574fda
TO
321 /**
322 * Recommend that sites use path-variables for their directories and URLs.
323 * @return array
324 */
325 public function checkUrlVariables() {
326 $messages = array();
327 $hasOldStyle = FALSE;
328 $settingNames = array(
329 'userFrameworkResourceURL',
330 'imageUploadURL',
331 'customCSSURL',
332 'extensionsURL',
333 );
334
335 foreach ($settingNames as $settingName) {
336 $settingValue = Civi::settings()->get($settingName);
337 if (!empty($settingValue) && $settingValue{0} != '[') {
338 $hasOldStyle = TRUE;
339 break;
340 }
341 }
342
343 if ($hasOldStyle) {
344 $message = new CRM_Utils_Check_Message(
345 __FUNCTION__,
346 ts('<a href="%1">Resource URLs</a> may use absolute paths, relative paths, or variables. Absolute paths are more difficult to maintain. To maximize portability, consider using a variable in each URL (eg "<tt>[cms.root]</tt>" or "<tt>[civicrm.files]</tt>").',
347 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', "reset=1"))),
348 ts('Resource URLs: Make them portable'),
349 \Psr\Log\LogLevel::NOTICE,
350 'fa-server'
351 );
352 $messages[] = $message;
353 }
354
355 return $messages;
356 }
357
358 /**
359 * Recommend that sites use path-variables for their directories and URLs.
360 * @return array
361 */
362 public function checkDirVariables() {
363 $messages = array();
364 $hasOldStyle = FALSE;
365 $settingNames = array(
366 'uploadDir',
367 'imageUploadDir',
368 'customFileUploadDir',
369 'customTemplateDir',
370 'customPHPPathDir',
371 'extensionsDir',
372 );
373
374 foreach ($settingNames as $settingName) {
375 $settingValue = Civi::settings()->get($settingName);
376 if (!empty($settingValue) && $settingValue{0} != '[') {
377 $hasOldStyle = TRUE;
378 break;
379 }
380 }
381
382 if ($hasOldStyle) {
383 $message = new CRM_Utils_Check_Message(
384 __FUNCTION__,
385 ts('<a href="%1">Directories</a> may use absolute paths, relative paths, or variables. Absolute paths are more difficult to maintain. To maximize portability, consider using a variable in each directory (eg "<tt>[cms.root]</tt>" or "<tt>[civicrm.files]</tt>").',
386 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', "reset=1"))),
387 ts('Directory Paths: Make them portable'),
388 \Psr\Log\LogLevel::NOTICE,
389 'fa-server'
390 );
391 $messages[] = $message;
392 }
393
394 return $messages;
395 }
396
3f0e59f6
AH
397 /**
398 * Check that important directories are writable.
399 *
400 * @return array
401 * Any CRM_Utils_Check_Message instances that need to be generated.
402 */
403 public function checkDirsWritable() {
404 $notWritable = array();
405
406 $config = CRM_Core_Config::singleton();
407 $directories = array(
408 'uploadDir' => ts('Temporary Files Directory'),
409 'imageUploadDir' => ts('Images Directory'),
410 'customFileUploadDir' => ts('Custom Files Directory'),
411 'extensionsDir' => ts('CiviCRM Extensions Directory'),
412 );
413
414 foreach ($directories as $directory => $label) {
415 $file = CRM_Utils_File::createFakeFile($config->$directory);
416
417 if ($file === FALSE) {
418 $notWritable[] = "$label ({$config->$directory})";
419 }
420 else {
421 $dirWithSlash = CRM_Utils_File::addTrailingSlash($config->$directory);
422 unlink($dirWithSlash . $file);
423 }
424 }
425
426 $messages = array();
427
428 if (!empty($notWritable)) {
429 $messages[] = new CRM_Utils_Check_Message(
430 __FUNCTION__,
431 ts('The %1 is not writable. Please check your file permissions.', array(
432 1 => implode(', ', $notWritable),
433 'count' => count($notWritable),
434 'plural' => 'The following directories are not writable: %1. Please check your file permissions.',
435 )),
436 ts('Directory not writable', array(
437 'count' => count($notWritable),
438 'plural' => 'Directories not writable',
439 )),
440 \Psr\Log\LogLevel::ERROR,
441 'fa-ban'
442 );
443 }
444
445 return $messages;
446 }
50574fda 447
fba5f6ac
AH
448 /**
449 * Checks if new versions are available
450 * @return array
451 */
fba5f6ac
AH
452 public function checkVersion() {
453 $messages = array();
e2fb6a98
CW
454 try {
455 $vc = new CRM_Utils_VersionCheck();
456 $vc->initialize();
457 }
458 catch (Exception $e) {
459 $messages[] = new CRM_Utils_Check_Message(
460 'checkVersionError',
461 ts('Directory %1 is not writable. Please change your file permissions.',
462 array(1 => dirname($vc->cacheFile))),
463 ts('Directory not writable'),
464 \Psr\Log\LogLevel::ERROR,
465 'fa-times-circle-o'
466 );
467 return $messages;
468 }
fba5f6ac 469
b864507b
CW
470 // Show a notice if the version_check job is disabled
471 if (empty($vc->cronJob['is_active'])) {
472 $args = empty($vc->cronJob['id']) ? array('reset' => 1) : array('reset' => 1, 'action' => 'update', 'id' => $vc->cronJob['id']);
540c3e63
CW
473 $messages[] = new CRM_Utils_Check_Message(
474 'checkVersionDisabled',
475 ts('The check for new versions of CiviCRM has been disabled. <a %1>Re-enable the scheduled job</a> to receive important security update notifications.', array(1 => 'href="' . CRM_Utils_System::url('civicrm/admin/job', $args) . '"')),
476 ts('Update Check Disabled'),
477 \Psr\Log\LogLevel::NOTICE,
478 'fa-times-circle-o'
479 );
480 }
481
83f064f2 482 if ($vc->isInfoAvailable) {
b864507b 483 $newerVersion = $vc->isNewerVersionAvailable();
83f064f2
CW
484 if ($newerVersion['version']) {
485 $vInfo = array(
486 1 => $newerVersion['version'],
487 2 => $vc->localVersion,
488 );
489 // LTS = long-term support version
490 if ($newerVersion['status'] == 'lts') {
491 $vInfo[1] .= ' ' . ts('(long-term support)');
492 }
493
494 if ($newerVersion['upgrade'] == 'security') {
495 // Security
496 $severity = \Psr\Log\LogLevel::CRITICAL;
497 $title = ts('CiviCRM Security Update Required');
498 $message = ts('New security release %1 is available. The site is currently running %2.', $vInfo);
499 }
500 elseif ($newerVersion['status'] == 'eol') {
501 // Warn about EOL
502 $severity = \Psr\Log\LogLevel::WARNING;
503 $title = ts('CiviCRM Update Needed');
504 $message = ts('New version %1 is available. The site is currently running %2, which has reached its end of life.', $vInfo);
505 }
506 else {
507 // For most new versions, just make them notice
508 $severity = \Psr\Log\LogLevel::NOTICE;
509 $title = ts('CiviCRM Update Available');
510 $message = ts('New version %1 is available. The site is currently running %2.', $vInfo);
511 }
06576a03 512 }
b864507b 513 elseif (!empty($vc->cronJob['is_active'])) {
83f064f2
CW
514 $vNum = $vc->localVersion;
515 // LTS = long-term support version
516 if ($newerVersion['status'] == 'lts') {
517 $vNum .= ' ' . ts('(long-term support)');
518 }
519
520 $severity = \Psr\Log\LogLevel::INFO;
521 $title = ts('CiviCRM Up-to-Date');
522 $message = ts('CiviCRM version %1 is up-to-date.', array(1 => $vNum));
d450a5f0
CW
523 }
524
540c3e63
CW
525 if (!empty($message)) {
526 $messages[] = new CRM_Utils_Check_Message(
527 __FUNCTION__,
528 $message,
529 $title,
530 $severity,
531 'fa-cloud-upload'
d450a5f0
CW
532 );
533 }
06576a03 534 }
fba5f6ac 535
06576a03 536 return $messages;
fba5f6ac 537 }
580ad3ef
AH
538
539 /**
540 * Checks if extensions are set up properly
541 * @return array
542 */
580ad3ef
AH
543 public function checkExtensions() {
544 $messages = array();
545 $extensionSystem = CRM_Extension_System::singleton();
546 $mapper = $extensionSystem->getMapper();
547 $manager = $extensionSystem->getManager();
580ad3ef
AH
548
549 if ($extensionSystem->getDefaultContainer()) {
550 $basedir = $extensionSystem->getDefaultContainer()->baseDir;
551 }
552
553 if (empty($basedir)) {
554 // no extension directory
555 $messages[] = new CRM_Utils_Check_Message(
165aab59 556 __FUNCTION__,
580ad3ef
AH
557 ts('Your extensions directory is not set. Click <a href="%1">here</a> to set the extensions directory.',
558 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', 'reset=1'))),
e2fb6a98 559 ts('Directory not writable'),
165aab59
CW
560 \Psr\Log\LogLevel::NOTICE,
561 'fa-plug'
580ad3ef
AH
562 );
563 return $messages;
564 }
565
566 if (!is_dir($basedir)) {
567 $messages[] = new CRM_Utils_Check_Message(
165aab59 568 __FUNCTION__,
9329d168
AH
569 ts('Your extensions directory path points to %1, which is not a directory. Please check your file system.',
570 array(1 => $basedir)),
580ad3ef 571 ts('Extensions directory incorrect'),
165aab59
CW
572 \Psr\Log\LogLevel::ERROR,
573 'fa-plug'
580ad3ef
AH
574 );
575 return $messages;
576 }
577 elseif (!is_writable($basedir)) {
578 $messages[] = new CRM_Utils_Check_Message(
165aab59 579 __FUNCTION__,
e2fb6a98 580 ts('Directory %1 is not writable. Please change your file permissions.',
9329d168 581 array(1 => $basedir)),
e2fb6a98 582 ts('Directory not writable'),
165aab59
CW
583 \Psr\Log\LogLevel::ERROR,
584 'fa-plug'
580ad3ef
AH
585 );
586 return $messages;
587 }
588
589 if (empty($extensionSystem->getDefaultContainer()->baseUrl)) {
590 $messages[] = new CRM_Utils_Check_Message(
165aab59 591 __FUNCTION__,
580ad3ef
AH
592 ts('The extensions URL is not properly set. Please go to the <a href="%1">URL setting page</a> and correct it.',
593 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
165aab59
CW
594 ts('Extensions url missing'),
595 \Psr\Log\LogLevel::ERROR,
596 'fa-plug'
580ad3ef
AH
597 );
598 return $messages;
599 }
600
b769826b
CW
601 if (!$extensionSystem->getBrowser()->isEnabled()) {
602 $messages[] = new CRM_Utils_Check_Message(
165aab59 603 __FUNCTION__,
b769826b
CW
604 ts('Not checking remote URL for extensions since ext_repo_url is set to false.'),
605 ts('Extensions check disabled'),
165aab59
CW
606 \Psr\Log\LogLevel::NOTICE,
607 'fa-plug'
b769826b
CW
608 );
609 return $messages;
610 }
611
612 try {
613 $remotes = $extensionSystem->getBrowser()->getExtensions();
614 }
615 catch (CRM_Extension_Exception $e) {
616 $messages[] = new CRM_Utils_Check_Message(
165aab59 617 __FUNCTION__,
b769826b
CW
618 $e->getMessage(),
619 ts('Extension download error'),
165aab59
CW
620 \Psr\Log\LogLevel::ERROR,
621 'fa-plug'
b769826b
CW
622 );
623 return $messages;
624 }
625
626 if (!$remotes) {
627 // CRM-13141 There may not be any compatible extensions available for the requested CiviCRM version + CMS. If so, $extdir is empty so just return a notice.
628 $messages[] = new CRM_Utils_Check_Message(
165aab59 629 __FUNCTION__,
b769826b
CW
630 ts('There are currently no extensions on the CiviCRM public extension directory which are compatible with version %1. If you want to install an extension which is not marked as compatible, you may be able to <a %2>download and install extensions manually</a> (depending on access to your web server).', array(
631 1 => CRM_Utils_System::majorVersion(),
632 2 => 'href="http://wiki.civicrm.org/confluence/display/CRMDOC/Extensions"',
633 )),
634 ts('No Extensions Available for this Version'),
165aab59
CW
635 \Psr\Log\LogLevel::NOTICE,
636 'fa-plug'
b769826b
CW
637 );
638 return $messages;
639 }
640
580ad3ef
AH
641 $keys = array_keys($manager->getStatuses());
642 sort($keys);
6e61248d 643 $updates = $errors = $okextensions = array();
48f03858 644
580ad3ef
AH
645 foreach ($keys as $key) {
646 try {
647 $obj = $mapper->keyToInfo($key);
648 }
649 catch (CRM_Extension_Exception $ex) {
6e61248d 650 $errors[] = ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key));
580ad3ef
AH
651 continue;
652 }
653 $row = CRM_Admin_Page_Extensions::createExtendedInfo($obj);
654 switch ($row['status']) {
655 case CRM_Extension_Manager::STATUS_INSTALLED_MISSING:
6e61248d 656 $errors[] = ts('%1 extension (%2) is installed but missing files.', array(1 => CRM_Utils_Array::value('label', $row), 2 => $key));
580ad3ef
AH
657 break;
658
659 case CRM_Extension_Manager::STATUS_INSTALLED:
48f03858 660 if (!empty($remotes[$key]) && version_compare($row['version'], $remotes[$key]->version, '<')) {
6e61248d 661 $updates[] = ts('%1 (%2) version %3 is installed. <a %4>Upgrade to version %5</a>.', array(
48f03858
CW
662 1 => CRM_Utils_Array::value('label', $row),
663 2 => $key,
664 3 => $row['version'],
665 4 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', "action=update&id=$key&key=$key") . '"',
95db6764 666 5 => $remotes[$key]->version,
48f03858
CW
667 ));
668 }
669 else {
670 if (empty($row['label'])) {
671 $okextensions[] = $key;
580ad3ef
AH
672 }
673 else {
48f03858
CW
674 $okextensions[] = ts('%1 (%2) version %3', array(
675 1 => $row['label'],
676 2 => $key,
677 3 => $row['version'],
678 ));
580ad3ef
AH
679 }
680 }
580ad3ef 681 break;
580ad3ef
AH
682 }
683 }
6e61248d
CW
684
685 if (!$okextensions && !$updates && !$errors) {
e2a3547b 686 $messages[] = new CRM_Utils_Check_Message(
c08d5b15 687 'extensionsOk',
6e61248d 688 ts('No extensions installed. <a %1>Browse available extensions</a>.', array(
81756b44 689 1 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"',
6e61248d
CW
690 )),
691 ts('Extensions'),
692 \Psr\Log\LogLevel::INFO,
693 'fa-plug'
e2a3547b 694 );
580ad3ef 695 }
6e61248d
CW
696
697 if ($errors) {
698 $messages[] = new CRM_Utils_Check_Message(
699 __FUNCTION__,
700 '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>',
701 ts('Extension Error'),
702 \Psr\Log\LogLevel::ERROR,
703 'fa-plug'
704 );
48f03858 705 }
6e61248d
CW
706
707 if ($updates) {
708 $messages[] = new CRM_Utils_Check_Message(
709 'extensionUpdates',
710 '<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
711 ts('Extension Update Available', array('plural' => '%count Extension Updates Available', 'count' => count($updates))),
712 \Psr\Log\LogLevel::WARNING,
713 'fa-plug'
714 );
580ad3ef 715 }
097c681e 716
6e61248d 717 if ($okextensions) {
c08d5b15
CW
718 if ($updates || $errors) {
719 $message = ts('1 extension is up-to-date:', array('plural' => '%count extensions are up-to-date:', 'count' => count($okextensions)));
720 }
721 else {
722 $message = ts('All extensions are up-to-date:');
723 }
6e61248d
CW
724 $messages[] = new CRM_Utils_Check_Message(
725 'extensionsOk',
c08d5b15 726 $message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
6e61248d
CW
727 ts('Extensions'),
728 \Psr\Log\LogLevel::INFO,
729 'fa-plug'
730 );
731 }
580ad3ef
AH
732
733 return $messages;
734 }
735
736
737 /**
4b540f18
CW
738 * Checks if there are pending extension upgrades.
739 *
580ad3ef
AH
740 * @return array
741 */
742 public function checkExtensionUpgrades() {
580ad3ef 743 if (CRM_Extension_Upgrades::hasPending()) {
4b540f18 744 $message = new CRM_Utils_Check_Message(
165aab59 745 __FUNCTION__,
4b540f18
CW
746 ts('Extension upgrades should be run as soon as possible.'),
747 ts('Extension Upgrades Pending'),
165aab59
CW
748 \Psr\Log\LogLevel::ERROR,
749 'fa-plug'
580ad3ef 750 );
4b540f18
CW
751 $message->addAction(
752 ts('Run Upgrades'),
753 ts('Run extension upgrades now?'),
754 'href',
755 array('path' => 'civicrm/admin/extensions/upgrade', 'query' => array('reset' => 1, 'destination' => CRM_Utils_System::url('civicrm/a/#/status')))
756 );
757 return array($message);
580ad3ef 758 }
4b540f18 759 return array();
580ad3ef
AH
760 }
761
762 /**
763 * Checks if CiviCRM database version is up-to-date
764 * @return array
765 */
580ad3ef
AH
766 public function checkDbVersion() {
767 $messages = array();
768 $dbVersion = CRM_Core_BAO_Domain::version();
769 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
770
771 if (!$dbVersion) {
772 // if db.ver missing
773 $messages[] = new CRM_Utils_Check_Message(
165aab59 774 __FUNCTION__,
580ad3ef
AH
775 ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.'),
776 ts('Database Version Missing'),
165aab59
CW
777 \Psr\Log\LogLevel::ERROR,
778 'fa-database'
580ad3ef
AH
779 );
780 }
781 elseif (!CRM_Utils_System::isVersionFormatValid($dbVersion)) {
782 $messages[] = new CRM_Utils_Check_Message(
165aab59 783 __FUNCTION__,
580ad3ef
AH
784 ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'),
785 ts('Database Version Invalid'),
165aab59
CW
786 \Psr\Log\LogLevel::ERROR,
787 'fa-database'
580ad3ef
AH
788 );
789 }
790 elseif (stripos($dbVersion, 'upgrade')) {
791 // if db.ver indicates a partially upgraded db
792 $messages[] = new CRM_Utils_Check_Message(
165aab59 793 __FUNCTION__,
580ad3ef
AH
794 ts('Database check failed - the database looks to have been partially upgraded. You must reload the database with the backup and try the <a href=\'%1\'>upgrade process</a> again.', array(1 => $upgradeUrl)),
795 ts('Database Partially Upgraded'),
165aab59
CW
796 \Psr\Log\LogLevel::ALERT,
797 'fa-database'
580ad3ef
AH
798 );
799 }
800 else {
801 $codeVersion = CRM_Utils_System::version();
802
803 // if db.ver < code.ver, time to upgrade
804 if (version_compare($dbVersion, $codeVersion) < 0) {
805 $messages[] = new CRM_Utils_Check_Message(
165aab59 806 __FUNCTION__,
580ad3ef
AH
807 ts('New codebase version detected. You must visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl)),
808 ts('Database Upgrade Required'),
165aab59
CW
809 \Psr\Log\LogLevel::ALERT,
810 'fa-database'
580ad3ef
AH
811 );
812 }
813
814 // if db.ver > code.ver, sth really wrong
815 if (version_compare($dbVersion, $codeVersion) > 0) {
816 $messages[] = new CRM_Utils_Check_Message(
165aab59 817 __FUNCTION__,
580ad3ef
AH
818 ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state.
819 You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase
820 you were using until you resolve this problem.<br/>OR if this is a manual install from git, you might want to fix civicrm-version.php file.',
821 array(1 => $dbVersion, 2 => $codeVersion)
822 ),
823 ts('Database In Unexpected Version'),
165aab59
CW
824 \Psr\Log\LogLevel::ERROR,
825 'fa-database'
580ad3ef
AH
826 );
827 }
828 }
829
830 return $messages;
831 }
832
833 /**
834 * ensure that all CiviCRM tables are InnoDB
835 * @return array
836 */
580ad3ef
AH
837 public function checkDbEngine() {
838 $messages = array();
839
840 if (CRM_Core_DAO::isDBMyISAM(150)) {
841 $messages[] = new CRM_Utils_Check_Message(
165aab59 842 __FUNCTION__,
580ad3ef
AH
843 ts('Your database is configured to use the MyISAM database engine. CiviCRM requires InnoDB. You will need to convert any MyISAM tables in your database to InnoDB. Using MyISAM tables will result in data integrity issues.'),
844 ts('MyISAM Database Engine'),
165aab59
CW
845 \Psr\Log\LogLevel::ERROR,
846 'fa-database'
580ad3ef
AH
847 );
848 }
849 return $messages;
850 }
851
28288426
CW
852 /**
853 * Check for required mbstring extension
854 * @return array
855 */
856 public function checkMbstring() {
857 $messages = array();
858
859 if (!function_exists('mb_substr')) {
860 $messages[] = new CRM_Utils_Check_Message(
861 __FUNCTION__,
ade9995e 862 ts('The PHP Multibyte String extension is needed for CiviCRM to correctly handle user input among other functionality. Ask your system administrator to install it.'),
28288426 863 ts('Missing mbstring Extension'),
ade9995e 864 \Psr\Log\LogLevel::WARNING,
28288426
CW
865 'fa-server'
866 );
867 }
868 return $messages;
869 }
870
f008885c
E
871 /**
872 * Check if environment is Production.
873 * @return array
874 */
875 public function checkEnvironment() {
876 $messages = array();
877
878 $environment = CRM_Core_Config::environment();
879 if ($environment != 'Production') {
880 $messages[] = new CRM_Utils_Check_Message(
881 __FUNCTION__,
882 ts('The environment of this CiviCRM instance is set to \'%1\'. Certain functionality like scheduled jobs has been disabled.', array(1 => $environment)),
883 ts('Non-Production Environment'),
884 \Psr\Log\LogLevel::ALERT,
885 'fa-bug'
886 );
887 }
888 return $messages;
889 }
890
69ebc0c0
J
891 /**
892 * Check that the resource URL points to the correct location.
893 * @return array
894 */
895 public function checkResourceUrl() {
896 $messages = array();
e997d152
J
897 // Skip when run during unit tests, you can't check without a CMS.
898 if (CRM_Core_Config::singleton()->userFramework == 'UnitTests') {
899 return $messages;
900 }
83ad0439
TB
901 // CRM-21629 Set User Agent to avoid being blocked by filters
902 stream_context_set_default(array(
903 'http' => array('user_agent' => 'CiviCRM'),
904 ));
905
69ebc0c0
J
906 // Does arrow.png exist where we expect it?
907 $arrowUrl = CRM_Core_Config::singleton()->userFrameworkResourceURL . 'packages/jquery/css/images/arrow.png';
908 $headers = get_headers($arrowUrl);
909 $fileExists = stripos($headers[0], "200 OK") ? 1 : 0;
910 if (!$fileExists) {
911 $messages[] = new CRM_Utils_Check_Message(
912 __FUNCTION__,
913 ts('The Resource URL is not set correctly. Please set the <a href="%1">CiviCRM Resource URL</a>.',
914 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
915 ts('Incorrect Resource URL'),
916 \Psr\Log\LogLevel::ERROR,
917 'fa-server'
918 );
919 }
920 return $messages;
921 }
922
5bc392e6 923}