Merge pull request #12210 from colemanw/dev/core#117
[civicrm-core.git] / CRM / Utils / Check / Component / Env.php
CommitLineData
1e927c45
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
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);
8ce83e54
KC
211 $domain = CRM_Core_BAO_Domain::getDomain();
212 $domainName = $domain->name;
213 $fixEmailUrl = CRM_Utils_System::url("civicrm/admin/options/from_email_address", "&reset=1");
214 $fixDomainName = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1");
1b366958
AH
215
216 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
217 if (!$domainName || $domainName == 'Default Domain Name') {
8ce83e54
KC
218 $msg = ts("Please enter your organization's <a href=\"%1\">name, primary address </a> and <a href=\"%2\">default FROM Email Address </a> (for system-generated emails).",
219 array(
220 1 => $fixDomainName,
221 2 => $fixEmailUrl,
222 )
223 );
1b366958
AH
224 }
225 else {
226 $msg = ts('Please enter a <a href="%1">default FROM Email Address</a> (for system-generated emails).',
227 array(1 => $fixEmailUrl));
228 }
229 }
230 elseif (!$domainName || $domainName == 'Default Domain Name') {
231 $msg = ts("Please enter your organization's <a href=\"%1\">name and primary address</a>.",
8ce83e54 232 array(1 => $fixDomainName));
1b366958 233 }
aacaa119
AH
234
235 if (!empty($msg)) {
236 $messages[] = new CRM_Utils_Check_Message(
165aab59 237 __FUNCTION__,
aacaa119
AH
238 $msg,
239 ts('Complete Setup'),
165aab59
CW
240 \Psr\Log\LogLevel::WARNING,
241 'fa-check-square-o'
aacaa119
AH
242 );
243 }
1b366958
AH
244
245 return $messages;
246 }
247
248 /**
249 * Checks if a default bounce handling mailbox is set up
250 * @return array
251 */
1b366958
AH
252 public function checkDefaultMailbox() {
253 $messages = array();
254 $config = CRM_Core_Config::singleton();
255
256 if (in_array('CiviMail', $config->enableComponents) &&
257 CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG"
258 ) {
259 $message = new CRM_Utils_Check_Message(
165aab59 260 __FUNCTION__,
aa96ce62 261 ts('Please configure a <a href="%1">default mailbox</a> for CiviMail.',
1b366958
AH
262 array(1 => CRM_Utils_System::url('civicrm/admin/mailSettings', "reset=1"))),
263 ts('Configure Default Mailbox'),
165aab59
CW
264 \Psr\Log\LogLevel::WARNING,
265 'fa-envelope'
1b366958 266 );
2a243675
CW
267 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('page' => 'user/advanced-configuration/email-system-configuration/', 'URLonly' => TRUE)) . '""';
268 $message->addHelp(
269 ts('A default mailbox must be configured for email bounce processing.') . '<br />' .
270 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
271 );
1b366958
AH
272 $messages[] = $message;
273 }
274
275 return $messages;
276 }
aa96ce62
AH
277
278 /**
279 * Checks if cron has run in a reasonable amount of time
280 * @return array
281 */
aa96ce62
AH
282 public function checkLastCron() {
283 $messages = array();
284
285 $statusPreference = new CRM_Core_DAO_StatusPreference();
286 $statusPreference->domain_id = CRM_Core_Config::domainID();
287 $statusPreference->name = 'checkLastCron';
288
0296367d
CW
289 if ($statusPreference->find(TRUE) && !empty($statusPreference->check_info)) {
290 $lastCron = $statusPreference->check_info;
fba5f6ac
AH
291 $msg = ts('Last cron run at %1.', array(1 => CRM_Utils_Date::customFormat(date('c', $lastCron))));
292 }
293 else {
294 $lastCron = 0;
295 $msg = ts('No cron runs have been recorded.');
296 }
aa96ce62 297
aa96ce62
AH
298 if ($lastCron > gmdate('U') - 3600) {
299 $messages[] = new CRM_Utils_Check_Message(
165aab59 300 __FUNCTION__,
aa96ce62
AH
301 $msg,
302 ts('Cron Running OK'),
165aab59
CW
303 \Psr\Log\LogLevel::INFO,
304 'fa-clock-o'
aa96ce62
AH
305 );
306 }
fba5f6ac 307 else {
aa96ce62 308 $message = new CRM_Utils_Check_Message(
165aab59 309 __FUNCTION__,
aa96ce62
AH
310 $msg,
311 ts('Cron Not Running'),
2a243675 312 ($lastCron > gmdate('U') - 86400) ? \Psr\Log\LogLevel::WARNING : \Psr\Log\LogLevel::ERROR,
165aab59 313 'fa-clock-o'
aa96ce62 314 );
2a243675
CW
315 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('resource' => 'wiki', 'page' => 'Managing Scheduled Jobs', 'URLonly' => TRUE)) . '""';
316 $message->addHelp(
317 ts('Configuring cron on your server is necessary for running scheduled jobs such as sending mail and scheduled reminders.') . '<br />' .
318 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
319 );
aa96ce62
AH
320 $messages[] = $message;
321 }
322
323 return $messages;
324 }
fba5f6ac 325
50574fda
TO
326 /**
327 * Recommend that sites use path-variables for their directories and URLs.
328 * @return array
329 */
330 public function checkUrlVariables() {
331 $messages = array();
332 $hasOldStyle = FALSE;
333 $settingNames = array(
334 'userFrameworkResourceURL',
335 'imageUploadURL',
336 'customCSSURL',
337 'extensionsURL',
338 );
339
340 foreach ($settingNames as $settingName) {
341 $settingValue = Civi::settings()->get($settingName);
342 if (!empty($settingValue) && $settingValue{0} != '[') {
343 $hasOldStyle = TRUE;
344 break;
345 }
346 }
347
348 if ($hasOldStyle) {
349 $message = new CRM_Utils_Check_Message(
350 __FUNCTION__,
351 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>").',
352 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', "reset=1"))),
353 ts('Resource URLs: Make them portable'),
354 \Psr\Log\LogLevel::NOTICE,
355 'fa-server'
356 );
357 $messages[] = $message;
358 }
359
360 return $messages;
361 }
362
363 /**
364 * Recommend that sites use path-variables for their directories and URLs.
365 * @return array
366 */
367 public function checkDirVariables() {
368 $messages = array();
369 $hasOldStyle = FALSE;
370 $settingNames = array(
371 'uploadDir',
372 'imageUploadDir',
373 'customFileUploadDir',
374 'customTemplateDir',
375 'customPHPPathDir',
376 'extensionsDir',
377 );
378
379 foreach ($settingNames as $settingName) {
380 $settingValue = Civi::settings()->get($settingName);
381 if (!empty($settingValue) && $settingValue{0} != '[') {
382 $hasOldStyle = TRUE;
383 break;
384 }
385 }
386
387 if ($hasOldStyle) {
388 $message = new CRM_Utils_Check_Message(
389 __FUNCTION__,
390 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>").',
391 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', "reset=1"))),
392 ts('Directory Paths: Make them portable'),
393 \Psr\Log\LogLevel::NOTICE,
394 'fa-server'
395 );
396 $messages[] = $message;
397 }
398
399 return $messages;
400 }
401
3f0e59f6
AH
402 /**
403 * Check that important directories are writable.
404 *
405 * @return array
406 * Any CRM_Utils_Check_Message instances that need to be generated.
407 */
408 public function checkDirsWritable() {
409 $notWritable = array();
410
411 $config = CRM_Core_Config::singleton();
412 $directories = array(
413 'uploadDir' => ts('Temporary Files Directory'),
414 'imageUploadDir' => ts('Images Directory'),
415 'customFileUploadDir' => ts('Custom Files Directory'),
3f0e59f6
AH
416 );
417
418 foreach ($directories as $directory => $label) {
419 $file = CRM_Utils_File::createFakeFile($config->$directory);
420
421 if ($file === FALSE) {
422 $notWritable[] = "$label ({$config->$directory})";
423 }
424 else {
425 $dirWithSlash = CRM_Utils_File::addTrailingSlash($config->$directory);
426 unlink($dirWithSlash . $file);
427 }
428 }
429
430 $messages = array();
431
432 if (!empty($notWritable)) {
433 $messages[] = new CRM_Utils_Check_Message(
434 __FUNCTION__,
435 ts('The %1 is not writable. Please check your file permissions.', array(
436 1 => implode(', ', $notWritable),
437 'count' => count($notWritable),
438 'plural' => 'The following directories are not writable: %1. Please check your file permissions.',
439 )),
440 ts('Directory not writable', array(
441 'count' => count($notWritable),
442 'plural' => 'Directories not writable',
443 )),
444 \Psr\Log\LogLevel::ERROR,
445 'fa-ban'
446 );
447 }
448
449 return $messages;
450 }
50574fda 451
fba5f6ac
AH
452 /**
453 * Checks if new versions are available
454 * @return array
455 */
fba5f6ac
AH
456 public function checkVersion() {
457 $messages = array();
e2fb6a98
CW
458 try {
459 $vc = new CRM_Utils_VersionCheck();
460 $vc->initialize();
461 }
462 catch (Exception $e) {
463 $messages[] = new CRM_Utils_Check_Message(
464 'checkVersionError',
465 ts('Directory %1 is not writable. Please change your file permissions.',
466 array(1 => dirname($vc->cacheFile))),
467 ts('Directory not writable'),
468 \Psr\Log\LogLevel::ERROR,
469 'fa-times-circle-o'
470 );
471 return $messages;
472 }
fba5f6ac 473
b864507b
CW
474 // Show a notice if the version_check job is disabled
475 if (empty($vc->cronJob['is_active'])) {
476 $args = empty($vc->cronJob['id']) ? array('reset' => 1) : array('reset' => 1, 'action' => 'update', 'id' => $vc->cronJob['id']);
540c3e63
CW
477 $messages[] = new CRM_Utils_Check_Message(
478 'checkVersionDisabled',
479 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) . '"')),
480 ts('Update Check Disabled'),
481 \Psr\Log\LogLevel::NOTICE,
482 'fa-times-circle-o'
483 );
484 }
485
83f064f2 486 if ($vc->isInfoAvailable) {
88790378
TO
487 $severities = array(
488 'info' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::INFO),
489 'notice' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::NOTICE) ,
490 'warning' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::WARNING) ,
491 'critical' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::CRITICAL),
492 );
493 foreach ($vc->getVersionMessages() as $msg) {
494 $messages[] = new CRM_Utils_Check_Message(__FUNCTION__ . '_' . $msg['name'],
495 $msg['message'], $msg['title'], $severities[$msg['severity']], 'fa-cloud-upload');
d450a5f0 496 }
06576a03 497 }
fba5f6ac 498
06576a03 499 return $messages;
fba5f6ac 500 }
580ad3ef
AH
501
502 /**
503 * Checks if extensions are set up properly
504 * @return array
505 */
580ad3ef
AH
506 public function checkExtensions() {
507 $messages = array();
508 $extensionSystem = CRM_Extension_System::singleton();
509 $mapper = $extensionSystem->getMapper();
510 $manager = $extensionSystem->getManager();
580ad3ef
AH
511
512 if ($extensionSystem->getDefaultContainer()) {
513 $basedir = $extensionSystem->getDefaultContainer()->baseDir;
514 }
515
516 if (empty($basedir)) {
517 // no extension directory
518 $messages[] = new CRM_Utils_Check_Message(
165aab59 519 __FUNCTION__,
580ad3ef
AH
520 ts('Your extensions directory is not set. Click <a href="%1">here</a> to set the extensions directory.',
521 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', 'reset=1'))),
e2fb6a98 522 ts('Directory not writable'),
165aab59
CW
523 \Psr\Log\LogLevel::NOTICE,
524 'fa-plug'
580ad3ef
AH
525 );
526 return $messages;
527 }
528
529 if (!is_dir($basedir)) {
530 $messages[] = new CRM_Utils_Check_Message(
165aab59 531 __FUNCTION__,
9329d168
AH
532 ts('Your extensions directory path points to %1, which is not a directory. Please check your file system.',
533 array(1 => $basedir)),
580ad3ef 534 ts('Extensions directory incorrect'),
165aab59
CW
535 \Psr\Log\LogLevel::ERROR,
536 'fa-plug'
580ad3ef
AH
537 );
538 return $messages;
539 }
540 elseif (!is_writable($basedir)) {
541 $messages[] = new CRM_Utils_Check_Message(
165aab59 542 __FUNCTION__,
599164fe 543 ts('Your extensions directory (%1) is read-only. If you would like to perform downloads or upgrades, then change the file permissions.',
9329d168 544 array(1 => $basedir)),
37b705a0
TO
545 ts('Read-Only Extensions'),
546 \Psr\Log\LogLevel::WARNING,
165aab59 547 'fa-plug'
580ad3ef
AH
548 );
549 return $messages;
550 }
551
552 if (empty($extensionSystem->getDefaultContainer()->baseUrl)) {
553 $messages[] = new CRM_Utils_Check_Message(
165aab59 554 __FUNCTION__,
580ad3ef
AH
555 ts('The extensions URL is not properly set. Please go to the <a href="%1">URL setting page</a> and correct it.',
556 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
165aab59
CW
557 ts('Extensions url missing'),
558 \Psr\Log\LogLevel::ERROR,
559 'fa-plug'
580ad3ef
AH
560 );
561 return $messages;
562 }
563
b769826b
CW
564 if (!$extensionSystem->getBrowser()->isEnabled()) {
565 $messages[] = new CRM_Utils_Check_Message(
165aab59 566 __FUNCTION__,
b769826b
CW
567 ts('Not checking remote URL for extensions since ext_repo_url is set to false.'),
568 ts('Extensions check disabled'),
165aab59
CW
569 \Psr\Log\LogLevel::NOTICE,
570 'fa-plug'
b769826b
CW
571 );
572 return $messages;
573 }
574
575 try {
576 $remotes = $extensionSystem->getBrowser()->getExtensions();
577 }
578 catch (CRM_Extension_Exception $e) {
579 $messages[] = new CRM_Utils_Check_Message(
165aab59 580 __FUNCTION__,
b769826b
CW
581 $e->getMessage(),
582 ts('Extension download error'),
165aab59
CW
583 \Psr\Log\LogLevel::ERROR,
584 'fa-plug'
b769826b
CW
585 );
586 return $messages;
587 }
588
589 if (!$remotes) {
590 // 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.
591 $messages[] = new CRM_Utils_Check_Message(
165aab59 592 __FUNCTION__,
b769826b
CW
593 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(
594 1 => CRM_Utils_System::majorVersion(),
595 2 => 'href="http://wiki.civicrm.org/confluence/display/CRMDOC/Extensions"',
596 )),
597 ts('No Extensions Available for this Version'),
165aab59
CW
598 \Psr\Log\LogLevel::NOTICE,
599 'fa-plug'
b769826b
CW
600 );
601 return $messages;
602 }
603
580ad3ef
AH
604 $keys = array_keys($manager->getStatuses());
605 sort($keys);
6e61248d 606 $updates = $errors = $okextensions = array();
48f03858 607
580ad3ef
AH
608 foreach ($keys as $key) {
609 try {
610 $obj = $mapper->keyToInfo($key);
611 }
612 catch (CRM_Extension_Exception $ex) {
6e61248d 613 $errors[] = ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key));
580ad3ef
AH
614 continue;
615 }
616 $row = CRM_Admin_Page_Extensions::createExtendedInfo($obj);
617 switch ($row['status']) {
618 case CRM_Extension_Manager::STATUS_INSTALLED_MISSING:
6e61248d 619 $errors[] = ts('%1 extension (%2) is installed but missing files.', array(1 => CRM_Utils_Array::value('label', $row), 2 => $key));
580ad3ef
AH
620 break;
621
622 case CRM_Extension_Manager::STATUS_INSTALLED:
48f03858 623 if (!empty($remotes[$key]) && version_compare($row['version'], $remotes[$key]->version, '<')) {
6e61248d 624 $updates[] = ts('%1 (%2) version %3 is installed. <a %4>Upgrade to version %5</a>.', array(
48f03858
CW
625 1 => CRM_Utils_Array::value('label', $row),
626 2 => $key,
627 3 => $row['version'],
628 4 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', "action=update&id=$key&key=$key") . '"',
95db6764 629 5 => $remotes[$key]->version,
48f03858
CW
630 ));
631 }
632 else {
633 if (empty($row['label'])) {
634 $okextensions[] = $key;
580ad3ef
AH
635 }
636 else {
48f03858
CW
637 $okextensions[] = ts('%1 (%2) version %3', array(
638 1 => $row['label'],
639 2 => $key,
640 3 => $row['version'],
641 ));
580ad3ef
AH
642 }
643 }
580ad3ef 644 break;
580ad3ef
AH
645 }
646 }
6e61248d
CW
647
648 if (!$okextensions && !$updates && !$errors) {
e2a3547b 649 $messages[] = new CRM_Utils_Check_Message(
c08d5b15 650 'extensionsOk',
6e61248d 651 ts('No extensions installed. <a %1>Browse available extensions</a>.', array(
81756b44 652 1 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"',
6e61248d
CW
653 )),
654 ts('Extensions'),
655 \Psr\Log\LogLevel::INFO,
656 'fa-plug'
e2a3547b 657 );
580ad3ef 658 }
6e61248d
CW
659
660 if ($errors) {
661 $messages[] = new CRM_Utils_Check_Message(
662 __FUNCTION__,
663 '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>',
664 ts('Extension Error'),
665 \Psr\Log\LogLevel::ERROR,
666 'fa-plug'
667 );
48f03858 668 }
6e61248d
CW
669
670 if ($updates) {
671 $messages[] = new CRM_Utils_Check_Message(
672 'extensionUpdates',
673 '<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
674 ts('Extension Update Available', array('plural' => '%count Extension Updates Available', 'count' => count($updates))),
675 \Psr\Log\LogLevel::WARNING,
676 'fa-plug'
677 );
580ad3ef 678 }
097c681e 679
6e61248d 680 if ($okextensions) {
c08d5b15
CW
681 if ($updates || $errors) {
682 $message = ts('1 extension is up-to-date:', array('plural' => '%count extensions are up-to-date:', 'count' => count($okextensions)));
683 }
684 else {
685 $message = ts('All extensions are up-to-date:');
686 }
6e61248d
CW
687 $messages[] = new CRM_Utils_Check_Message(
688 'extensionsOk',
c08d5b15 689 $message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
6e61248d
CW
690 ts('Extensions'),
691 \Psr\Log\LogLevel::INFO,
692 'fa-plug'
693 );
694 }
580ad3ef
AH
695
696 return $messages;
697 }
698
699
700 /**
4b540f18
CW
701 * Checks if there are pending extension upgrades.
702 *
580ad3ef
AH
703 * @return array
704 */
705 public function checkExtensionUpgrades() {
580ad3ef 706 if (CRM_Extension_Upgrades::hasPending()) {
4b540f18 707 $message = new CRM_Utils_Check_Message(
165aab59 708 __FUNCTION__,
4b540f18
CW
709 ts('Extension upgrades should be run as soon as possible.'),
710 ts('Extension Upgrades Pending'),
165aab59
CW
711 \Psr\Log\LogLevel::ERROR,
712 'fa-plug'
580ad3ef 713 );
4b540f18
CW
714 $message->addAction(
715 ts('Run Upgrades'),
716 ts('Run extension upgrades now?'),
717 'href',
718 array('path' => 'civicrm/admin/extensions/upgrade', 'query' => array('reset' => 1, 'destination' => CRM_Utils_System::url('civicrm/a/#/status')))
719 );
720 return array($message);
580ad3ef 721 }
4b540f18 722 return array();
580ad3ef
AH
723 }
724
725 /**
726 * Checks if CiviCRM database version is up-to-date
727 * @return array
728 */
580ad3ef
AH
729 public function checkDbVersion() {
730 $messages = array();
731 $dbVersion = CRM_Core_BAO_Domain::version();
732 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
733
734 if (!$dbVersion) {
735 // if db.ver missing
736 $messages[] = new CRM_Utils_Check_Message(
165aab59 737 __FUNCTION__,
580ad3ef
AH
738 ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.'),
739 ts('Database Version Missing'),
165aab59
CW
740 \Psr\Log\LogLevel::ERROR,
741 'fa-database'
580ad3ef
AH
742 );
743 }
744 elseif (!CRM_Utils_System::isVersionFormatValid($dbVersion)) {
745 $messages[] = new CRM_Utils_Check_Message(
165aab59 746 __FUNCTION__,
580ad3ef
AH
747 ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'),
748 ts('Database Version Invalid'),
165aab59
CW
749 \Psr\Log\LogLevel::ERROR,
750 'fa-database'
580ad3ef
AH
751 );
752 }
753 elseif (stripos($dbVersion, 'upgrade')) {
754 // if db.ver indicates a partially upgraded db
755 $messages[] = new CRM_Utils_Check_Message(
165aab59 756 __FUNCTION__,
580ad3ef
AH
757 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)),
758 ts('Database Partially Upgraded'),
165aab59
CW
759 \Psr\Log\LogLevel::ALERT,
760 'fa-database'
580ad3ef
AH
761 );
762 }
763 else {
764 $codeVersion = CRM_Utils_System::version();
765
766 // if db.ver < code.ver, time to upgrade
767 if (version_compare($dbVersion, $codeVersion) < 0) {
768 $messages[] = new CRM_Utils_Check_Message(
165aab59 769 __FUNCTION__,
580ad3ef
AH
770 ts('New codebase version detected. You must visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl)),
771 ts('Database Upgrade Required'),
165aab59
CW
772 \Psr\Log\LogLevel::ALERT,
773 'fa-database'
580ad3ef
AH
774 );
775 }
776
777 // if db.ver > code.ver, sth really wrong
778 if (version_compare($dbVersion, $codeVersion) > 0) {
779 $messages[] = new CRM_Utils_Check_Message(
165aab59 780 __FUNCTION__,
580ad3ef
AH
781 ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state.
782 You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase
783 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.',
784 array(1 => $dbVersion, 2 => $codeVersion)
785 ),
786 ts('Database In Unexpected Version'),
165aab59
CW
787 \Psr\Log\LogLevel::ERROR,
788 'fa-database'
580ad3ef
AH
789 );
790 }
791 }
792
793 return $messages;
794 }
795
796 /**
797 * ensure that all CiviCRM tables are InnoDB
798 * @return array
799 */
580ad3ef
AH
800 public function checkDbEngine() {
801 $messages = array();
802
803 if (CRM_Core_DAO::isDBMyISAM(150)) {
804 $messages[] = new CRM_Utils_Check_Message(
165aab59 805 __FUNCTION__,
580ad3ef
AH
806 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.'),
807 ts('MyISAM Database Engine'),
165aab59
CW
808 \Psr\Log\LogLevel::ERROR,
809 'fa-database'
580ad3ef
AH
810 );
811 }
812 return $messages;
813 }
814
765e99a6
JP
815 /**
816 * ensure reply id is set to any default value
817 * @return array
818 */
819 public function checkReplyIdForMailing() {
820 $messages = array();
821
822 if (!CRM_Mailing_PseudoConstant::defaultComponent('Reply', '')) {
823 $messages[] = new CRM_Utils_Check_Message(
824 __FUNCTION__,
825 ts('Reply Auto Responder is not set to any default value in <a %1>Headers, Footers, and Automated Messages</a>. This will disable the submit operation on any mailing created from CiviMail.', array(1 => 'href="' . CRM_Utils_System::url('civicrm/admin/component', 'reset=1') . '"')),
826 ts('No Default value for Auto Responder.'),
827 \Psr\Log\LogLevel::WARNING,
828 'fa-reply'
829 );
830 }
831 return $messages;
832 }
833
28288426
CW
834 /**
835 * Check for required mbstring extension
836 * @return array
837 */
838 public function checkMbstring() {
839 $messages = array();
840
841 if (!function_exists('mb_substr')) {
842 $messages[] = new CRM_Utils_Check_Message(
843 __FUNCTION__,
ade9995e 844 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 845 ts('Missing mbstring Extension'),
ade9995e 846 \Psr\Log\LogLevel::WARNING,
28288426
CW
847 'fa-server'
848 );
849 }
850 return $messages;
851 }
852
f008885c
E
853 /**
854 * Check if environment is Production.
855 * @return array
856 */
857 public function checkEnvironment() {
858 $messages = array();
859
860 $environment = CRM_Core_Config::environment();
861 if ($environment != 'Production') {
862 $messages[] = new CRM_Utils_Check_Message(
863 __FUNCTION__,
864 ts('The environment of this CiviCRM instance is set to \'%1\'. Certain functionality like scheduled jobs has been disabled.', array(1 => $environment)),
865 ts('Non-Production Environment'),
866 \Psr\Log\LogLevel::ALERT,
867 'fa-bug'
868 );
869 }
870 return $messages;
871 }
872
69ebc0c0
J
873 /**
874 * Check that the resource URL points to the correct location.
875 * @return array
876 */
877 public function checkResourceUrl() {
878 $messages = array();
e997d152
J
879 // Skip when run during unit tests, you can't check without a CMS.
880 if (CRM_Core_Config::singleton()->userFramework == 'UnitTests') {
881 return $messages;
882 }
83ad0439
TB
883 // CRM-21629 Set User Agent to avoid being blocked by filters
884 stream_context_set_default(array(
885 'http' => array('user_agent' => 'CiviCRM'),
886 ));
887
69ebc0c0
J
888 // Does arrow.png exist where we expect it?
889 $arrowUrl = CRM_Core_Config::singleton()->userFrameworkResourceURL . 'packages/jquery/css/images/arrow.png';
890 $headers = get_headers($arrowUrl);
891 $fileExists = stripos($headers[0], "200 OK") ? 1 : 0;
892 if (!$fileExists) {
893 $messages[] = new CRM_Utils_Check_Message(
894 __FUNCTION__,
895 ts('The Resource URL is not set correctly. Please set the <a href="%1">CiviCRM Resource URL</a>.',
896 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
897 ts('Incorrect Resource URL'),
898 \Psr\Log\LogLevel::ERROR,
899 'fa-server'
900 );
901 }
902 return $messages;
903 }
904
5bc392e6 905}