Create a temporary table because test is running inside a transaction.
[civicrm-core.git] / CRM / Utils / Check / Component / Env.php
CommitLineData
1e927c45
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
1e927c45 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
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
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
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__,
96fdb289 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 preferred 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
d5d56ec1 123 /**
124 * @return array
125 */
126 public function checkPhpEcrypt() {
127 $messages = array();
1184d56f 128 $mailingBackend = Civi::settings()->get('mailing_backend');
129 if (!is_array($mailingBackend)
130 || !isset($mailingBackend['outBound_option'])
131 || $mailingBackend['outBound_option'] != CRM_Mailing_Config::OUTBOUND_OPTION_SMTP
132 || !CRM_Utils_Array::value('smtpAuth', $mailingBackend)
133 ) {
134 return $messages;
135 }
136
d5d56ec1 137 $test_pass = 'iAmARandomString';
138 $encrypted_test_pass = CRM_Utils_Crypt::encrypt($test_pass);
139 if ($encrypted_test_pass == base64_encode($test_pass)) {
140 $messages[] = new CRM_Utils_Check_Message(
141 __FUNCTION__,
1184d56f 142 ts('Your PHP does not include the mcrypt encryption functions. Your SMTP password will not be stored encrypted, and if you have recently upgraded from a PHP that stored it with encryption, it will not be decrypted correctly.'
d5d56ec1 143 ),
144 ts('PHP Missing Extension "mcrypt"'),
145 \Psr\Log\LogLevel::WARNING,
146 'fa-server'
147 );
148 }
149 return $messages;
150 }
151
7342d7c4
TO
152 /**
153 * Check that the MySQL time settings match the PHP time settings.
154 *
155 * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings
156 */
1e927c45
TO
157 public function checkMysqlTime() {
158 $messages = array();
159
160 $phpNow = date('Y-m-d H:i');
161 $sqlNow = CRM_Core_DAO::singleValueQuery("SELECT date_format(now(), '%Y-%m-%d %H:%i')");
8010540a 162 if (!CRM_Utils_Time::isEqual($phpNow, $sqlNow, 2.5 * 60)) {
1e927c45 163 $messages[] = new CRM_Utils_Check_Message(
165aab59 164 __FUNCTION__,
1e927c45 165 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 166 1 => CRM_Utils_System::getWikiBaseURL() . 'checkMysqlTime',
1e927c45
TO
167 2 => $sqlNow,
168 3 => $phpNow,
169 )),
1b366958 170 ts('Timestamp Mismatch'),
165aab59
CW
171 \Psr\Log\LogLevel::ERROR,
172 'fa-server'
1e927c45
TO
173 );
174 }
175
176 return $messages;
177 }
7342d7c4 178
5bc392e6
EM
179 /**
180 * @return array
181 */
7342d7c4 182 public function checkDebug() {
7342d7c4
TO
183 $config = CRM_Core_Config::singleton();
184 if ($config->debug) {
4b540f18 185 $message = new CRM_Utils_Check_Message(
165aab59 186 __FUNCTION__,
7342d7c4
TO
187 ts('Warning: Debug is enabled in <a href="%1">system settings</a>. This should not be enabled on production servers.',
188 array(1 => CRM_Utils_System::url('civicrm/admin/setting/debug', 'reset=1'))),
1b366958 189 ts('Debug Mode Enabled'),
165aab59
CW
190 \Psr\Log\LogLevel::WARNING,
191 'fa-bug'
7342d7c4 192 );
4b540f18
CW
193 $message->addAction(
194 ts('Disable Debug Mode'),
195 ts('Disable debug mode now?'),
196 'api3',
197 array('Setting', 'create', array('debug_enabled' => 0))
198 );
199 return array($message);
7342d7c4
TO
200 }
201
4b540f18 202 return array();
7342d7c4
TO
203 }
204
5bc392e6
EM
205 /**
206 * @return array
207 */
7342d7c4
TO
208 public function checkOutboundMail() {
209 $messages = array();
210
aaffa79f 211 $mailingInfo = Civi::settings()->get('mailing_backend');
7342d7c4
TO
212 if (($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB
213 || (defined('CIVICRM_MAIL_LOG') && CIVICRM_MAIL_LOG)
214 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED
215 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MOCK)
216 ) {
217 $messages[] = new CRM_Utils_Check_Message(
165aab59 218 __FUNCTION__,
7342d7c4
TO
219 ts('Warning: Outbound email is disabled in <a href="%1">system settings</a>. Proper settings should be enabled on production servers.',
220 array(1 => CRM_Utils_System::url('civicrm/admin/setting/smtp', 'reset=1'))),
1b366958 221 ts('Outbound Email Disabled'),
165aab59
CW
222 \Psr\Log\LogLevel::WARNING,
223 'fa-envelope'
7342d7c4
TO
224 );
225 }
226
227 return $messages;
228 }
96025800 229
1b366958
AH
230 /**
231 * Check that domain email and org name are set
232 * @return array
233 */
1b366958
AH
234 public function checkDomainNameEmail() {
235 $messages = array();
236
237 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(TRUE);
8ce83e54
KC
238 $domain = CRM_Core_BAO_Domain::getDomain();
239 $domainName = $domain->name;
240 $fixEmailUrl = CRM_Utils_System::url("civicrm/admin/options/from_email_address", "&reset=1");
241 $fixDomainName = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1");
1b366958
AH
242
243 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
244 if (!$domainName || $domainName == 'Default Domain Name') {
8ce83e54
KC
245 $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).",
246 array(
247 1 => $fixDomainName,
248 2 => $fixEmailUrl,
249 )
250 );
1b366958
AH
251 }
252 else {
253 $msg = ts('Please enter a <a href="%1">default FROM Email Address</a> (for system-generated emails).',
254 array(1 => $fixEmailUrl));
255 }
256 }
257 elseif (!$domainName || $domainName == 'Default Domain Name') {
258 $msg = ts("Please enter your organization's <a href=\"%1\">name and primary address</a>.",
8ce83e54 259 array(1 => $fixDomainName));
1b366958 260 }
aacaa119
AH
261
262 if (!empty($msg)) {
263 $messages[] = new CRM_Utils_Check_Message(
165aab59 264 __FUNCTION__,
aacaa119
AH
265 $msg,
266 ts('Complete Setup'),
165aab59
CW
267 \Psr\Log\LogLevel::WARNING,
268 'fa-check-square-o'
aacaa119
AH
269 );
270 }
1b366958
AH
271
272 return $messages;
273 }
274
275 /**
276 * Checks if a default bounce handling mailbox is set up
277 * @return array
278 */
1b366958
AH
279 public function checkDefaultMailbox() {
280 $messages = array();
281 $config = CRM_Core_Config::singleton();
282
283 if (in_array('CiviMail', $config->enableComponents) &&
284 CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG"
285 ) {
286 $message = new CRM_Utils_Check_Message(
165aab59 287 __FUNCTION__,
aa96ce62 288 ts('Please configure a <a href="%1">default mailbox</a> for CiviMail.',
1b366958
AH
289 array(1 => CRM_Utils_System::url('civicrm/admin/mailSettings', "reset=1"))),
290 ts('Configure Default Mailbox'),
165aab59
CW
291 \Psr\Log\LogLevel::WARNING,
292 'fa-envelope'
1b366958 293 );
2a243675
CW
294 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('page' => 'user/advanced-configuration/email-system-configuration/', 'URLonly' => TRUE)) . '""';
295 $message->addHelp(
296 ts('A default mailbox must be configured for email bounce processing.') . '<br />' .
297 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
298 );
1b366958
AH
299 $messages[] = $message;
300 }
301
302 return $messages;
303 }
aa96ce62
AH
304
305 /**
306 * Checks if cron has run in a reasonable amount of time
307 * @return array
308 */
aa96ce62
AH
309 public function checkLastCron() {
310 $messages = array();
311
312 $statusPreference = new CRM_Core_DAO_StatusPreference();
313 $statusPreference->domain_id = CRM_Core_Config::domainID();
314 $statusPreference->name = 'checkLastCron';
315
0296367d
CW
316 if ($statusPreference->find(TRUE) && !empty($statusPreference->check_info)) {
317 $lastCron = $statusPreference->check_info;
fba5f6ac
AH
318 $msg = ts('Last cron run at %1.', array(1 => CRM_Utils_Date::customFormat(date('c', $lastCron))));
319 }
320 else {
321 $lastCron = 0;
322 $msg = ts('No cron runs have been recorded.');
323 }
aa96ce62 324
aa96ce62
AH
325 if ($lastCron > gmdate('U') - 3600) {
326 $messages[] = new CRM_Utils_Check_Message(
165aab59 327 __FUNCTION__,
aa96ce62
AH
328 $msg,
329 ts('Cron Running OK'),
165aab59
CW
330 \Psr\Log\LogLevel::INFO,
331 'fa-clock-o'
aa96ce62
AH
332 );
333 }
fba5f6ac 334 else {
aa96ce62 335 $message = new CRM_Utils_Check_Message(
165aab59 336 __FUNCTION__,
aa96ce62
AH
337 $msg,
338 ts('Cron Not Running'),
2a243675 339 ($lastCron > gmdate('U') - 86400) ? \Psr\Log\LogLevel::WARNING : \Psr\Log\LogLevel::ERROR,
165aab59 340 'fa-clock-o'
aa96ce62 341 );
2a243675
CW
342 $docUrl = 'target="_blank" href="' . CRM_Utils_System::docURL(array('resource' => 'wiki', 'page' => 'Managing Scheduled Jobs', 'URLonly' => TRUE)) . '""';
343 $message->addHelp(
344 ts('Configuring cron on your server is necessary for running scheduled jobs such as sending mail and scheduled reminders.') . '<br />' .
345 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
346 );
aa96ce62
AH
347 $messages[] = $message;
348 }
349
350 return $messages;
351 }
fba5f6ac 352
50574fda
TO
353 /**
354 * Recommend that sites use path-variables for their directories and URLs.
355 * @return array
356 */
357 public function checkUrlVariables() {
358 $messages = array();
359 $hasOldStyle = FALSE;
360 $settingNames = array(
361 'userFrameworkResourceURL',
362 'imageUploadURL',
363 'customCSSURL',
364 'extensionsURL',
365 );
366
367 foreach ($settingNames as $settingName) {
368 $settingValue = Civi::settings()->get($settingName);
369 if (!empty($settingValue) && $settingValue{0} != '[') {
370 $hasOldStyle = TRUE;
371 break;
372 }
373 }
374
375 if ($hasOldStyle) {
376 $message = new CRM_Utils_Check_Message(
377 __FUNCTION__,
378 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>").',
379 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', "reset=1"))),
380 ts('Resource URLs: Make them portable'),
381 \Psr\Log\LogLevel::NOTICE,
382 'fa-server'
383 );
384 $messages[] = $message;
385 }
386
387 return $messages;
388 }
389
390 /**
391 * Recommend that sites use path-variables for their directories and URLs.
392 * @return array
393 */
394 public function checkDirVariables() {
395 $messages = array();
396 $hasOldStyle = FALSE;
397 $settingNames = array(
398 'uploadDir',
399 'imageUploadDir',
400 'customFileUploadDir',
401 'customTemplateDir',
402 'customPHPPathDir',
403 'extensionsDir',
404 );
405
406 foreach ($settingNames as $settingName) {
407 $settingValue = Civi::settings()->get($settingName);
408 if (!empty($settingValue) && $settingValue{0} != '[') {
409 $hasOldStyle = TRUE;
410 break;
411 }
412 }
413
414 if ($hasOldStyle) {
415 $message = new CRM_Utils_Check_Message(
416 __FUNCTION__,
417 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>").',
418 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', "reset=1"))),
419 ts('Directory Paths: Make them portable'),
420 \Psr\Log\LogLevel::NOTICE,
421 'fa-server'
422 );
423 $messages[] = $message;
424 }
425
426 return $messages;
427 }
428
3f0e59f6
AH
429 /**
430 * Check that important directories are writable.
431 *
432 * @return array
433 * Any CRM_Utils_Check_Message instances that need to be generated.
434 */
435 public function checkDirsWritable() {
436 $notWritable = array();
437
438 $config = CRM_Core_Config::singleton();
439 $directories = array(
440 'uploadDir' => ts('Temporary Files Directory'),
441 'imageUploadDir' => ts('Images Directory'),
442 'customFileUploadDir' => ts('Custom Files Directory'),
3f0e59f6
AH
443 );
444
445 foreach ($directories as $directory => $label) {
446 $file = CRM_Utils_File::createFakeFile($config->$directory);
447
448 if ($file === FALSE) {
449 $notWritable[] = "$label ({$config->$directory})";
450 }
451 else {
452 $dirWithSlash = CRM_Utils_File::addTrailingSlash($config->$directory);
453 unlink($dirWithSlash . $file);
454 }
455 }
456
457 $messages = array();
458
459 if (!empty($notWritable)) {
460 $messages[] = new CRM_Utils_Check_Message(
461 __FUNCTION__,
462 ts('The %1 is not writable. Please check your file permissions.', array(
463 1 => implode(', ', $notWritable),
464 'count' => count($notWritable),
465 'plural' => 'The following directories are not writable: %1. Please check your file permissions.',
466 )),
467 ts('Directory not writable', array(
468 'count' => count($notWritable),
469 'plural' => 'Directories not writable',
470 )),
471 \Psr\Log\LogLevel::ERROR,
472 'fa-ban'
473 );
474 }
475
476 return $messages;
477 }
50574fda 478
fba5f6ac
AH
479 /**
480 * Checks if new versions are available
481 * @return array
482 */
fba5f6ac
AH
483 public function checkVersion() {
484 $messages = array();
e2fb6a98
CW
485 try {
486 $vc = new CRM_Utils_VersionCheck();
487 $vc->initialize();
488 }
489 catch (Exception $e) {
490 $messages[] = new CRM_Utils_Check_Message(
491 'checkVersionError',
492 ts('Directory %1 is not writable. Please change your file permissions.',
493 array(1 => dirname($vc->cacheFile))),
494 ts('Directory not writable'),
495 \Psr\Log\LogLevel::ERROR,
496 'fa-times-circle-o'
497 );
498 return $messages;
499 }
fba5f6ac 500
b864507b
CW
501 // Show a notice if the version_check job is disabled
502 if (empty($vc->cronJob['is_active'])) {
503 $args = empty($vc->cronJob['id']) ? array('reset' => 1) : array('reset' => 1, 'action' => 'update', 'id' => $vc->cronJob['id']);
540c3e63
CW
504 $messages[] = new CRM_Utils_Check_Message(
505 'checkVersionDisabled',
506 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) . '"')),
507 ts('Update Check Disabled'),
508 \Psr\Log\LogLevel::NOTICE,
509 'fa-times-circle-o'
510 );
511 }
512
83f064f2 513 if ($vc->isInfoAvailable) {
88790378
TO
514 $severities = array(
515 'info' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::INFO),
516 'notice' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::NOTICE) ,
517 'warning' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::WARNING) ,
518 'critical' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::CRITICAL),
519 );
520 foreach ($vc->getVersionMessages() as $msg) {
521 $messages[] = new CRM_Utils_Check_Message(__FUNCTION__ . '_' . $msg['name'],
522 $msg['message'], $msg['title'], $severities[$msg['severity']], 'fa-cloud-upload');
d450a5f0 523 }
06576a03 524 }
fba5f6ac 525
06576a03 526 return $messages;
fba5f6ac 527 }
580ad3ef
AH
528
529 /**
530 * Checks if extensions are set up properly
531 * @return array
532 */
580ad3ef
AH
533 public function checkExtensions() {
534 $messages = array();
535 $extensionSystem = CRM_Extension_System::singleton();
536 $mapper = $extensionSystem->getMapper();
537 $manager = $extensionSystem->getManager();
580ad3ef
AH
538
539 if ($extensionSystem->getDefaultContainer()) {
540 $basedir = $extensionSystem->getDefaultContainer()->baseDir;
541 }
542
543 if (empty($basedir)) {
544 // no extension directory
545 $messages[] = new CRM_Utils_Check_Message(
165aab59 546 __FUNCTION__,
580ad3ef
AH
547 ts('Your extensions directory is not set. Click <a href="%1">here</a> to set the extensions directory.',
548 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', 'reset=1'))),
e2fb6a98 549 ts('Directory not writable'),
165aab59
CW
550 \Psr\Log\LogLevel::NOTICE,
551 'fa-plug'
580ad3ef
AH
552 );
553 return $messages;
554 }
555
556 if (!is_dir($basedir)) {
557 $messages[] = new CRM_Utils_Check_Message(
165aab59 558 __FUNCTION__,
9329d168
AH
559 ts('Your extensions directory path points to %1, which is not a directory. Please check your file system.',
560 array(1 => $basedir)),
580ad3ef 561 ts('Extensions directory incorrect'),
165aab59
CW
562 \Psr\Log\LogLevel::ERROR,
563 'fa-plug'
580ad3ef
AH
564 );
565 return $messages;
566 }
567 elseif (!is_writable($basedir)) {
568 $messages[] = new CRM_Utils_Check_Message(
698721fc 569 __FUNCTION__ . 'Writable',
599164fe 570 ts('Your extensions directory (%1) is read-only. If you would like to perform downloads or upgrades, then change the file permissions.',
9329d168 571 array(1 => $basedir)),
37b705a0 572 ts('Read-Only Extensions'),
6e7ad3dc 573 \Psr\Log\LogLevel::NOTICE,
165aab59 574 'fa-plug'
580ad3ef 575 );
580ad3ef
AH
576 }
577
578 if (empty($extensionSystem->getDefaultContainer()->baseUrl)) {
579 $messages[] = new CRM_Utils_Check_Message(
698721fc 580 __FUNCTION__ . 'URL',
580ad3ef
AH
581 ts('The extensions URL is not properly set. Please go to the <a href="%1">URL setting page</a> and correct it.',
582 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
165aab59
CW
583 ts('Extensions url missing'),
584 \Psr\Log\LogLevel::ERROR,
585 'fa-plug'
580ad3ef 586 );
580ad3ef
AH
587 }
588
b769826b
CW
589 if (!$extensionSystem->getBrowser()->isEnabled()) {
590 $messages[] = new CRM_Utils_Check_Message(
165aab59 591 __FUNCTION__,
b769826b
CW
592 ts('Not checking remote URL for extensions since ext_repo_url is set to false.'),
593 ts('Extensions check disabled'),
165aab59
CW
594 \Psr\Log\LogLevel::NOTICE,
595 'fa-plug'
b769826b
CW
596 );
597 return $messages;
598 }
599
600 try {
601 $remotes = $extensionSystem->getBrowser()->getExtensions();
602 }
603 catch (CRM_Extension_Exception $e) {
604 $messages[] = new CRM_Utils_Check_Message(
165aab59 605 __FUNCTION__,
b769826b
CW
606 $e->getMessage(),
607 ts('Extension download error'),
165aab59
CW
608 \Psr\Log\LogLevel::ERROR,
609 'fa-plug'
b769826b
CW
610 );
611 return $messages;
612 }
613
614 if (!$remotes) {
615 // 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.
616 $messages[] = new CRM_Utils_Check_Message(
165aab59 617 __FUNCTION__,
b769826b
CW
618 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(
619 1 => CRM_Utils_System::majorVersion(),
620 2 => 'href="http://wiki.civicrm.org/confluence/display/CRMDOC/Extensions"',
621 )),
622 ts('No Extensions Available for this Version'),
165aab59
CW
623 \Psr\Log\LogLevel::NOTICE,
624 'fa-plug'
b769826b
CW
625 );
626 return $messages;
627 }
628
580ad3ef
AH
629 $keys = array_keys($manager->getStatuses());
630 sort($keys);
6e61248d 631 $updates = $errors = $okextensions = array();
48f03858 632
580ad3ef
AH
633 foreach ($keys as $key) {
634 try {
635 $obj = $mapper->keyToInfo($key);
636 }
637 catch (CRM_Extension_Exception $ex) {
6e61248d 638 $errors[] = ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key));
580ad3ef
AH
639 continue;
640 }
641 $row = CRM_Admin_Page_Extensions::createExtendedInfo($obj);
642 switch ($row['status']) {
643 case CRM_Extension_Manager::STATUS_INSTALLED_MISSING:
6e61248d 644 $errors[] = ts('%1 extension (%2) is installed but missing files.', array(1 => CRM_Utils_Array::value('label', $row), 2 => $key));
580ad3ef
AH
645 break;
646
647 case CRM_Extension_Manager::STATUS_INSTALLED:
48f03858 648 if (!empty($remotes[$key]) && version_compare($row['version'], $remotes[$key]->version, '<')) {
6e61248d 649 $updates[] = ts('%1 (%2) version %3 is installed. <a %4>Upgrade to version %5</a>.', array(
48f03858
CW
650 1 => CRM_Utils_Array::value('label', $row),
651 2 => $key,
652 3 => $row['version'],
653 4 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', "action=update&id=$key&key=$key") . '"',
95db6764 654 5 => $remotes[$key]->version,
48f03858
CW
655 ));
656 }
657 else {
658 if (empty($row['label'])) {
659 $okextensions[] = $key;
580ad3ef
AH
660 }
661 else {
48f03858
CW
662 $okextensions[] = ts('%1 (%2) version %3', array(
663 1 => $row['label'],
664 2 => $key,
665 3 => $row['version'],
666 ));
580ad3ef
AH
667 }
668 }
580ad3ef 669 break;
580ad3ef
AH
670 }
671 }
6e61248d
CW
672
673 if (!$okextensions && !$updates && !$errors) {
e2a3547b 674 $messages[] = new CRM_Utils_Check_Message(
c08d5b15 675 'extensionsOk',
6e61248d 676 ts('No extensions installed. <a %1>Browse available extensions</a>.', array(
81756b44 677 1 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"',
6e61248d
CW
678 )),
679 ts('Extensions'),
680 \Psr\Log\LogLevel::INFO,
681 'fa-plug'
e2a3547b 682 );
580ad3ef 683 }
6e61248d
CW
684
685 if ($errors) {
686 $messages[] = new CRM_Utils_Check_Message(
698721fc 687 __FUNCTION__ . 'Error',
6e61248d
CW
688 '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>',
689 ts('Extension Error'),
690 \Psr\Log\LogLevel::ERROR,
691 'fa-plug'
692 );
48f03858 693 }
6e61248d
CW
694
695 if ($updates) {
696 $messages[] = new CRM_Utils_Check_Message(
697 'extensionUpdates',
698 '<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
699 ts('Extension Update Available', array('plural' => '%count Extension Updates Available', 'count' => count($updates))),
700 \Psr\Log\LogLevel::WARNING,
701 'fa-plug'
702 );
580ad3ef 703 }
097c681e 704
6e61248d 705 if ($okextensions) {
c08d5b15
CW
706 if ($updates || $errors) {
707 $message = ts('1 extension is up-to-date:', array('plural' => '%count extensions are up-to-date:', 'count' => count($okextensions)));
708 }
709 else {
710 $message = ts('All extensions are up-to-date:');
711 }
6e61248d
CW
712 $messages[] = new CRM_Utils_Check_Message(
713 'extensionsOk',
c08d5b15 714 $message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
6e61248d
CW
715 ts('Extensions'),
716 \Psr\Log\LogLevel::INFO,
717 'fa-plug'
718 );
719 }
580ad3ef
AH
720
721 return $messages;
722 }
723
724
725 /**
4b540f18
CW
726 * Checks if there are pending extension upgrades.
727 *
580ad3ef
AH
728 * @return array
729 */
730 public function checkExtensionUpgrades() {
580ad3ef 731 if (CRM_Extension_Upgrades::hasPending()) {
4b540f18 732 $message = new CRM_Utils_Check_Message(
165aab59 733 __FUNCTION__,
4b540f18
CW
734 ts('Extension upgrades should be run as soon as possible.'),
735 ts('Extension Upgrades Pending'),
165aab59
CW
736 \Psr\Log\LogLevel::ERROR,
737 'fa-plug'
580ad3ef 738 );
4b540f18
CW
739 $message->addAction(
740 ts('Run Upgrades'),
741 ts('Run extension upgrades now?'),
742 'href',
743 array('path' => 'civicrm/admin/extensions/upgrade', 'query' => array('reset' => 1, 'destination' => CRM_Utils_System::url('civicrm/a/#/status')))
744 );
745 return array($message);
580ad3ef 746 }
4b540f18 747 return array();
580ad3ef
AH
748 }
749
750 /**
751 * Checks if CiviCRM database version is up-to-date
752 * @return array
753 */
580ad3ef
AH
754 public function checkDbVersion() {
755 $messages = array();
756 $dbVersion = CRM_Core_BAO_Domain::version();
757 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
758
759 if (!$dbVersion) {
760 // if db.ver missing
761 $messages[] = new CRM_Utils_Check_Message(
165aab59 762 __FUNCTION__,
580ad3ef
AH
763 ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.'),
764 ts('Database Version Missing'),
165aab59
CW
765 \Psr\Log\LogLevel::ERROR,
766 'fa-database'
580ad3ef
AH
767 );
768 }
769 elseif (!CRM_Utils_System::isVersionFormatValid($dbVersion)) {
770 $messages[] = new CRM_Utils_Check_Message(
165aab59 771 __FUNCTION__,
580ad3ef
AH
772 ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'),
773 ts('Database Version Invalid'),
165aab59
CW
774 \Psr\Log\LogLevel::ERROR,
775 'fa-database'
580ad3ef
AH
776 );
777 }
778 elseif (stripos($dbVersion, 'upgrade')) {
779 // if db.ver indicates a partially upgraded db
780 $messages[] = new CRM_Utils_Check_Message(
165aab59 781 __FUNCTION__,
580ad3ef
AH
782 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)),
783 ts('Database Partially Upgraded'),
165aab59
CW
784 \Psr\Log\LogLevel::ALERT,
785 'fa-database'
580ad3ef
AH
786 );
787 }
788 else {
789 $codeVersion = CRM_Utils_System::version();
790
791 // if db.ver < code.ver, time to upgrade
792 if (version_compare($dbVersion, $codeVersion) < 0) {
793 $messages[] = new CRM_Utils_Check_Message(
165aab59 794 __FUNCTION__,
580ad3ef
AH
795 ts('New codebase version detected. You must visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl)),
796 ts('Database Upgrade Required'),
165aab59
CW
797 \Psr\Log\LogLevel::ALERT,
798 'fa-database'
580ad3ef
AH
799 );
800 }
801
802 // if db.ver > code.ver, sth really wrong
803 if (version_compare($dbVersion, $codeVersion) > 0) {
804 $messages[] = new CRM_Utils_Check_Message(
165aab59 805 __FUNCTION__,
580ad3ef
AH
806 ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state.
807 You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase
808 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.',
809 array(1 => $dbVersion, 2 => $codeVersion)
810 ),
811 ts('Database In Unexpected Version'),
165aab59
CW
812 \Psr\Log\LogLevel::ERROR,
813 'fa-database'
580ad3ef
AH
814 );
815 }
816 }
817
818 return $messages;
819 }
820
821 /**
822 * ensure that all CiviCRM tables are InnoDB
823 * @return array
824 */
580ad3ef
AH
825 public function checkDbEngine() {
826 $messages = array();
827
828 if (CRM_Core_DAO::isDBMyISAM(150)) {
829 $messages[] = new CRM_Utils_Check_Message(
165aab59 830 __FUNCTION__,
580ad3ef
AH
831 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.'),
832 ts('MyISAM Database Engine'),
165aab59
CW
833 \Psr\Log\LogLevel::ERROR,
834 'fa-database'
580ad3ef
AH
835 );
836 }
837 return $messages;
838 }
839
765e99a6
JP
840 /**
841 * ensure reply id is set to any default value
842 * @return array
843 */
844 public function checkReplyIdForMailing() {
845 $messages = array();
846
847 if (!CRM_Mailing_PseudoConstant::defaultComponent('Reply', '')) {
848 $messages[] = new CRM_Utils_Check_Message(
849 __FUNCTION__,
850 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') . '"')),
851 ts('No Default value for Auto Responder.'),
852 \Psr\Log\LogLevel::WARNING,
853 'fa-reply'
854 );
855 }
856 return $messages;
857 }
858
28288426
CW
859 /**
860 * Check for required mbstring extension
861 * @return array
862 */
863 public function checkMbstring() {
864 $messages = array();
865
866 if (!function_exists('mb_substr')) {
867 $messages[] = new CRM_Utils_Check_Message(
868 __FUNCTION__,
ade9995e 869 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 870 ts('Missing mbstring Extension'),
ade9995e 871 \Psr\Log\LogLevel::WARNING,
28288426
CW
872 'fa-server'
873 );
874 }
875 return $messages;
876 }
877
f008885c
E
878 /**
879 * Check if environment is Production.
880 * @return array
881 */
882 public function checkEnvironment() {
883 $messages = array();
884
885 $environment = CRM_Core_Config::environment();
886 if ($environment != 'Production') {
887 $messages[] = new CRM_Utils_Check_Message(
888 __FUNCTION__,
889 ts('The environment of this CiviCRM instance is set to \'%1\'. Certain functionality like scheduled jobs has been disabled.', array(1 => $environment)),
890 ts('Non-Production Environment'),
891 \Psr\Log\LogLevel::ALERT,
892 'fa-bug'
893 );
894 }
895 return $messages;
896 }
897
69ebc0c0
J
898 /**
899 * Check that the resource URL points to the correct location.
900 * @return array
901 */
902 public function checkResourceUrl() {
903 $messages = array();
e997d152
J
904 // Skip when run during unit tests, you can't check without a CMS.
905 if (CRM_Core_Config::singleton()->userFramework == 'UnitTests') {
906 return $messages;
907 }
83ad0439
TB
908 // CRM-21629 Set User Agent to avoid being blocked by filters
909 stream_context_set_default(array(
910 'http' => array('user_agent' => 'CiviCRM'),
911 ));
912
69ebc0c0
J
913 // Does arrow.png exist where we expect it?
914 $arrowUrl = CRM_Core_Config::singleton()->userFrameworkResourceURL . 'packages/jquery/css/images/arrow.png';
915 $headers = get_headers($arrowUrl);
916 $fileExists = stripos($headers[0], "200 OK") ? 1 : 0;
47bb2b94 917 if ($fileExists === FALSE) {
69ebc0c0
J
918 $messages[] = new CRM_Utils_Check_Message(
919 __FUNCTION__,
920 ts('The Resource URL is not set correctly. Please set the <a href="%1">CiviCRM Resource URL</a>.',
921 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
922 ts('Incorrect Resource URL'),
923 \Psr\Log\LogLevel::ERROR,
924 'fa-server'
925 );
926 }
927 return $messages;
928 }
929
75615982 930 /**
931 * Check for utf8mb4 support by MySQL.
932 *
933 * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings
934 */
935 public function checkMysqlUtf8mb4() {
936 $messages = array();
937
938 if (CRM_Core_DAO::getConnection()->phptype != 'mysqli') {
939 return $messages;
940 }
941
942 try {
c35aabb7 943 // Create a temporary table to avoid implicit commit.
944 CRM_Core_DAO::executeQuery('CREATE TEMPORARY TABLE civicrm_utf8mb4_test (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB');
945 CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE civicrm_utf8mb4_test');
75615982 946 }
45978e6d 947 catch (PEAR_Exception $e) {
75615982 948 $messages[] = new CRM_Utils_Check_Message(
949 __FUNCTION__,
950 ts('Future versions of CiviCRM may require MySQL utf8mb4 support. It is recommended, though not yet required, to configure your MySQL server for utf8mb4 support. You will need the following MySQL server configuration: innodb_large_prefix=true innodb_file_format=barracuda innodb_file_per_table=true'),
951 ts('MySQL utf8mb4 Support'),
952 \Psr\Log\LogLevel::WARNING,
953 'fa-database'
954 );
955 }
956 // Ensure that the MySQL driver supports utf8mb4 encoding.
957 $version = mysqli_get_client_info(CRM_Core_DAO::getConnection()->connection);
958 if (strpos($version, 'mysqlnd') !== FALSE) {
959 // The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
960 $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
961 if (version_compare($version, '5.0.9', '<')) {
962 $messages[] = new CRM_Utils_Check_Message(
963 __FUNCTION__,
964 ts('It is recommended, though not yet required, to upgrade your PHP MySQL driver (mysqlnd) to >= 5.0.9 for utf8mb4 support.'),
965 ts('PHP MySQL Driver (mysqlnd)'),
966 \Psr\Log\LogLevel::WARNING,
967 'fa-server'
968 );
969 }
970 }
971 else {
972 // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
973 if (version_compare($version, '5.5.3', '<')) {
974 $messages[] = new CRM_Utils_Check_Message(
975 __FUNCTION__,
976 ts('It is recommended, though not yet required, to upgrade your PHP MySQL driver (libmysqlclient) to >= 5.0.9 for utf8mb4 support.'),
977 ts('PHP MySQL Driver (libmysqlclient)'),
978 \Psr\Log\LogLevel::WARNING,
979 'fa-server'
980 );
981 }
982 }
983
984 return $messages;
985 }
986
5bc392e6 987}