3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2016 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2016
33 class CRM_Utils_Check_Component_Env
extends CRM_Utils_Check_Component
{
38 public function checkPhpVersion() {
41 if (version_compare(phpversion(), CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
) >= 0) {
42 $messages[] = new CRM_Utils_Check_Message(
44 ts('This system uses PHP version %1 which meets or exceeds the minimum recommendation of %2.',
47 2 => CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
,
50 \Psr\Log\LogLevel
::INFO
,
54 elseif (version_compare(phpversion(), CRM_Upgrade_Incremental_General
::MIN_DEFECT_PHP_VER
) >= 0) {
55 $messages[] = new CRM_Utils_Check_Message(
57 ts('This system uses PHP version %1. While this meets the minimum requirements for CiviCRM to function, upgrading to PHP version %2 or newer is recommended for maximum compatibility.',
60 2 => CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
,
61 3 => CRM_Upgrade_Incremental_General
::MIN_DEFECT_PHP_VER
,
63 ts('PHP Out-of-Date'),
64 \Psr\Log\LogLevel
::NOTICE
,
69 $messages[] = new CRM_Utils_Check_Message(
71 ts('This system uses PHP version %1. CiviCRM can be installed on this version, but some specific features are known to fail or degrade. Version %3 is the bare minimum to avoid known issues, and version %2 is recommended.',
74 2 => CRM_Upgrade_Incremental_General
::MIN_RECOMMENDED_PHP_VER
,
75 3 => CRM_Upgrade_Incremental_General
::MIN_DEFECT_PHP_VER
,
77 ts('PHP Out-of-Date'),
78 \Psr\Log\LogLevel
::WARNING
,
89 public function checkPhpMysqli() {
92 if (!extension_loaded('mysqli')) {
93 $messages[] = new CRM_Utils_Check_Message(
95 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>.',
97 1 => 'https://civicrm.org/blog/totten/psa-please-verify-php-extension-mysqli',
100 ts('Forward Compatibility: Enable "mysqli"'),
101 \Psr\Log\LogLevel
::WARNING
,
110 * Check that the MySQL time settings match the PHP time settings.
112 * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings
114 public function checkMysqlTime() {
115 //CRM-19115 - Always set MySQL time before checking it.
116 CRM_Core_Config
::singleton()->userSystem
->setMySQLTimeZone();
119 $phpNow = date('Y-m-d H:i');
120 $sqlNow = CRM_Core_DAO
::singleValueQuery("SELECT date_format(now(), '%Y-%m-%d %H:%i')");
121 if (!CRM_Utils_Time
::isEqual($phpNow, $sqlNow, 2.5 * 60)) {
122 $messages[] = new CRM_Utils_Check_Message(
124 ts('Timestamps reported by MySQL (eg "%2") and PHP (eg "%3" ) are mismatched.<br /><a href="%1">Read more about this warning</a>', array(
125 1 => CRM_Utils_System
::getWikiBaseURL() . 'checkMysqlTime',
129 ts('Timestamp Mismatch'),
130 \Psr\Log\LogLevel
::ERROR
,
141 public function checkDebug() {
144 $config = CRM_Core_Config
::singleton();
145 if ($config->debug
) {
146 $messages[] = new CRM_Utils_Check_Message(
148 ts('Warning: Debug is enabled in <a href="%1">system settings</a>. This should not be enabled on production servers.',
149 array(1 => CRM_Utils_System
::url('civicrm/admin/setting/debug', 'reset=1'))),
150 ts('Debug Mode Enabled'),
151 \Psr\Log\LogLevel
::WARNING
,
162 public function checkOutboundMail() {
165 $mailingInfo = Civi
::settings()->get('mailing_backend');
166 if (($mailingInfo['outBound_option'] == CRM_Mailing_Config
::OUTBOUND_OPTION_REDIRECT_TO_DB
167 ||
(defined('CIVICRM_MAIL_LOG') && CIVICRM_MAIL_LOG
)
168 ||
$mailingInfo['outBound_option'] == CRM_Mailing_Config
::OUTBOUND_OPTION_DISABLED
169 ||
$mailingInfo['outBound_option'] == CRM_Mailing_Config
::OUTBOUND_OPTION_MOCK
)
171 $messages[] = new CRM_Utils_Check_Message(
173 ts('Warning: Outbound email is disabled in <a href="%1">system settings</a>. Proper settings should be enabled on production servers.',
174 array(1 => CRM_Utils_System
::url('civicrm/admin/setting/smtp', 'reset=1'))),
175 ts('Outbound Email Disabled'),
176 \Psr\Log\LogLevel
::WARNING
,
185 * Check that domain email and org name are set
188 public function checkDomainNameEmail() {
191 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain
::getNameAndEmail(TRUE);
192 $domain = CRM_Core_BAO_Domain
::getDomain();
193 $domainName = $domain->name
;
194 $fixEmailUrl = CRM_Utils_System
::url("civicrm/admin/domain", "action=update&reset=1");
196 if (!$domainEmailAddress ||
$domainEmailAddress == 'info@EXAMPLE.ORG') {
197 if (!$domainName ||
$domainName == 'Default Domain Name') {
198 $msg = ts("Please enter your organization's <a href=\"%1\">name, primary address, and default FROM Email Address</a> (for system-generated emails).",
199 array(1 => $fixEmailUrl));
202 $msg = ts('Please enter a <a href="%1">default FROM Email Address</a> (for system-generated emails).',
203 array(1 => $fixEmailUrl));
206 elseif (!$domainName ||
$domainName == 'Default Domain Name') {
207 $msg = ts("Please enter your organization's <a href=\"%1\">name and primary address</a>.",
208 array(1 => $fixEmailUrl));
212 $messages[] = new CRM_Utils_Check_Message(
215 ts('Complete Setup'),
216 \Psr\Log\LogLevel
::WARNING
,
225 * Checks if a default bounce handling mailbox is set up
228 public function checkDefaultMailbox() {
230 $config = CRM_Core_Config
::singleton();
232 if (in_array('CiviMail', $config->enableComponents
) &&
233 CRM_Core_BAO_MailSettings
::defaultDomain() == "EXAMPLE.ORG"
235 $message = new CRM_Utils_Check_Message(
237 ts('Please configure a <a href="%1">default mailbox</a> for CiviMail.',
238 array(1 => CRM_Utils_System
::url('civicrm/admin/mailSettings', "reset=1"))),
239 ts('Configure Default Mailbox'),
240 \Psr\Log\LogLevel
::WARNING
,
243 $docUrl = 'target="_blank" href="' . CRM_Utils_System
::docURL(array('page' => 'user/advanced-configuration/email-system-configuration/', 'URLonly' => TRUE)) . '""';
245 ts('A default mailbox must be configured for email bounce processing.') . '<br />' .
246 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
248 $messages[] = $message;
255 * Checks if cron has run in a reasonable amount of time
258 public function checkLastCron() {
261 $statusPreference = new CRM_Core_DAO_StatusPreference();
262 $statusPreference->domain_id
= CRM_Core_Config
::domainID();
263 $statusPreference->name
= 'checkLastCron';
265 if ($statusPreference->find(TRUE) && !empty($statusPreference->check_info
)) {
266 $lastCron = $statusPreference->check_info
;
267 $msg = ts('Last cron run at %1.', array(1 => CRM_Utils_Date
::customFormat(date('c', $lastCron))));
271 $msg = ts('No cron runs have been recorded.');
274 if ($lastCron > gmdate('U') - 3600) {
275 $messages[] = new CRM_Utils_Check_Message(
278 ts('Cron Running OK'),
279 \Psr\Log\LogLevel
::INFO
,
284 $message = new CRM_Utils_Check_Message(
287 ts('Cron Not Running'),
288 ($lastCron > gmdate('U') - 86400) ? \Psr\Log\LogLevel
::WARNING
: \Psr\Log\LogLevel
::ERROR
,
291 $docUrl = 'target="_blank" href="' . CRM_Utils_System
::docURL(array('resource' => 'wiki', 'page' => 'Managing Scheduled Jobs', 'URLonly' => TRUE)) . '""';
293 ts('Configuring cron on your server is necessary for running scheduled jobs such as sending mail and scheduled reminders.') . '<br />' .
294 ts("Learn more in the <a %1>online documentation</a>.", array(1 => $docUrl))
296 $messages[] = $message;
303 * Checks if new versions are available
306 public function checkVersion() {
309 $vc = new CRM_Utils_VersionCheck();
312 catch (Exception
$e) {
313 $messages[] = new CRM_Utils_Check_Message(
315 ts('Directory %1 is not writable. Please change your file permissions.',
316 array(1 => dirname($vc->cacheFile
))),
317 ts('Directory not writable'),
318 \Psr\Log\LogLevel
::ERROR
,
324 // Show a notice if the version_check job is disabled
325 if (empty($vc->cronJob
['is_active'])) {
326 $args = empty($vc->cronJob
['id']) ?
array('reset' => 1) : array('reset' => 1, 'action' => 'update', 'id' => $vc->cronJob
['id']);
327 $messages[] = new CRM_Utils_Check_Message(
328 'checkVersionDisabled',
329 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) . '"')),
330 ts('Update Check Disabled'),
331 \Psr\Log\LogLevel
::NOTICE
,
336 if ($vc->isInfoAvailable
) {
337 $newerVersion = $vc->isNewerVersionAvailable();
338 if ($newerVersion['version']) {
340 1 => $newerVersion['version'],
341 2 => $vc->localVersion
,
343 // LTS = long-term support version
344 if ($newerVersion['status'] == 'lts') {
345 $vInfo[1] .= ' ' . ts('(long-term support)');
348 if ($newerVersion['upgrade'] == 'security') {
350 $severity = \Psr\Log\LogLevel
::CRITICAL
;
351 $title = ts('CiviCRM Security Update Required');
352 $message = ts('New security release %1 is available. The site is currently running %2.', $vInfo);
354 elseif ($newerVersion['status'] == 'eol') {
356 $severity = \Psr\Log\LogLevel
::WARNING
;
357 $title = ts('CiviCRM Update Needed');
358 $message = ts('New version %1 is available. The site is currently running %2, which has reached its end of life.', $vInfo);
361 // For most new versions, just make them notice
362 $severity = \Psr\Log\LogLevel
::NOTICE
;
363 $title = ts('CiviCRM Update Available');
364 $message = ts('New version %1 is available. The site is currently running %2.', $vInfo);
367 elseif (!empty($vc->cronJob
['is_active'])) {
368 $vNum = $vc->localVersion
;
369 // LTS = long-term support version
370 if ($newerVersion['status'] == 'lts') {
371 $vNum .= ' ' . ts('(long-term support)');
374 $severity = \Psr\Log\LogLevel
::INFO
;
375 $title = ts('CiviCRM Up-to-Date');
376 $message = ts('CiviCRM version %1 is up-to-date.', array(1 => $vNum));
379 if (!empty($message)) {
380 $messages[] = new CRM_Utils_Check_Message(
394 * Checks if extensions are set up properly
397 public function checkExtensions() {
399 $extensionSystem = CRM_Extension_System
::singleton();
400 $mapper = $extensionSystem->getMapper();
401 $manager = $extensionSystem->getManager();
403 if ($extensionSystem->getDefaultContainer()) {
404 $basedir = $extensionSystem->getDefaultContainer()->baseDir
;
407 if (empty($basedir)) {
408 // no extension directory
409 $messages[] = new CRM_Utils_Check_Message(
411 ts('Your extensions directory is not set. Click <a href="%1">here</a> to set the extensions directory.',
412 array(1 => CRM_Utils_System
::url('civicrm/admin/setting/path', 'reset=1'))),
413 ts('Directory not writable'),
414 \Psr\Log\LogLevel
::NOTICE
,
420 if (!is_dir($basedir)) {
421 $messages[] = new CRM_Utils_Check_Message(
423 ts('Your extensions directory path points to %1, which is not a directory. Please check your file system.',
424 array(1 => $basedir)),
425 ts('Extensions directory incorrect'),
426 \Psr\Log\LogLevel
::ERROR
,
431 elseif (!is_writable($basedir)) {
432 $messages[] = new CRM_Utils_Check_Message(
434 ts('Directory %1 is not writable. Please change your file permissions.',
435 array(1 => $basedir)),
436 ts('Directory not writable'),
437 \Psr\Log\LogLevel
::ERROR
,
443 if (empty($extensionSystem->getDefaultContainer()->baseUrl
)) {
444 $messages[] = new CRM_Utils_Check_Message(
446 ts('The extensions URL is not properly set. Please go to the <a href="%1">URL setting page</a> and correct it.',
447 array(1 => CRM_Utils_System
::url('civicrm/admin/setting/url', 'reset=1'))),
448 ts('Extensions url missing'),
449 \Psr\Log\LogLevel
::ERROR
,
455 if (!$extensionSystem->getBrowser()->isEnabled()) {
456 $messages[] = new CRM_Utils_Check_Message(
458 ts('Not checking remote URL for extensions since ext_repo_url is set to false.'),
459 ts('Extensions check disabled'),
460 \Psr\Log\LogLevel
::NOTICE
,
467 $remotes = $extensionSystem->getBrowser()->getExtensions();
469 catch (CRM_Extension_Exception
$e) {
470 $messages[] = new CRM_Utils_Check_Message(
473 ts('Extension download error'),
474 \Psr\Log\LogLevel
::ERROR
,
481 // 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.
482 $messages[] = new CRM_Utils_Check_Message(
484 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(
485 1 => CRM_Utils_System
::majorVersion(),
486 2 => 'href="http://wiki.civicrm.org/confluence/display/CRMDOC/Extensions"',
488 ts('No Extensions Available for this Version'),
489 \Psr\Log\LogLevel
::NOTICE
,
495 $keys = array_keys($manager->getStatuses());
497 $updates = $errors = $okextensions = array();
499 foreach ($keys as $key) {
501 $obj = $mapper->keyToInfo($key);
503 catch (CRM_Extension_Exception
$ex) {
504 $errors[] = ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key));
507 $row = CRM_Admin_Page_Extensions
::createExtendedInfo($obj);
508 switch ($row['status']) {
509 case CRM_Extension_Manager
::STATUS_INSTALLED_MISSING
:
510 $errors[] = ts('%1 extension (%2) is installed but missing files.', array(1 => CRM_Utils_Array
::value('label', $row), 2 => $key));
513 case CRM_Extension_Manager
::STATUS_INSTALLED
:
514 if (!empty($remotes[$key]) && version_compare($row['version'], $remotes[$key]->version
, '<')) {
515 $updates[] = ts('%1 (%2) version %3 is installed. <a %4>Upgrade to version %5</a>.', array(
516 1 => CRM_Utils_Array
::value('label', $row),
518 3 => $row['version'],
519 4 => 'href="' . CRM_Utils_System
::url('civicrm/admin/extensions', "action=update&id=$key&key=$key") . '"',
520 5 => $remotes[$key]->version
,
524 if (empty($row['label'])) {
525 $okextensions[] = $key;
528 $okextensions[] = ts('%1 (%2) version %3', array(
531 3 => $row['version'],
539 if (!$okextensions && !$updates && !$errors) {
540 $messages[] = new CRM_Utils_Check_Message(
542 ts('No extensions installed. <a %1>Browse available extensions</a>.', array(
543 1 => 'href="' . CRM_Utils_System
::url('civicrm/admin/extensions', 'reset=1') . '"',
546 \Psr\Log\LogLevel
::INFO
,
552 $messages[] = new CRM_Utils_Check_Message(
554 '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>',
555 ts('Extension Error'),
556 \Psr\Log\LogLevel
::ERROR
,
562 $messages[] = new CRM_Utils_Check_Message(
564 '<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
565 ts('Extension Update Available', array('plural' => '%count Extension Updates Available', 'count' => count($updates))),
566 \Psr\Log\LogLevel
::WARNING
,
572 if ($updates ||
$errors) {
573 $message = ts('1 extension is up-to-date:', array('plural' => '%count extensions are up-to-date:', 'count' => count($okextensions)));
576 $message = ts('All extensions are up-to-date:');
578 $messages[] = new CRM_Utils_Check_Message(
580 $message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
582 \Psr\Log\LogLevel
::INFO
,
592 * Checks if extensions are set up properly
595 public function checkExtensionUpgrades() {
598 if (CRM_Extension_Upgrades
::hasPending()) {
599 $messages[] = new CRM_Utils_Check_Message(
601 ts('Extension upgrades are pending. Please visit <a href="%1">the upgrade page</a> to run them.',
602 array(1 => CRM_Utils_System
::url('civicrm/admin/extensions/upgrade', 'reset=1'))),
603 ts('Run Extension Upgrades'),
604 \Psr\Log\LogLevel
::ERROR
,
612 * Checks if CiviCRM database version is up-to-date
615 public function checkDbVersion() {
617 $dbVersion = CRM_Core_BAO_Domain
::version();
618 $upgradeUrl = CRM_Utils_System
::url("civicrm/upgrade", "reset=1");
622 $messages[] = new CRM_Utils_Check_Message(
624 ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.'),
625 ts('Database Version Missing'),
626 \Psr\Log\LogLevel
::ERROR
,
630 elseif (!CRM_Utils_System
::isVersionFormatValid($dbVersion)) {
631 $messages[] = new CRM_Utils_Check_Message(
633 ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'),
634 ts('Database Version Invalid'),
635 \Psr\Log\LogLevel
::ERROR
,
639 elseif (stripos($dbVersion, 'upgrade')) {
640 // if db.ver indicates a partially upgraded db
641 $messages[] = new CRM_Utils_Check_Message(
643 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)),
644 ts('Database Partially Upgraded'),
645 \Psr\Log\LogLevel
::ALERT
,
650 $codeVersion = CRM_Utils_System
::version();
652 // if db.ver < code.ver, time to upgrade
653 if (version_compare($dbVersion, $codeVersion) < 0) {
654 $messages[] = new CRM_Utils_Check_Message(
656 ts('New codebase version detected. You must visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl)),
657 ts('Database Upgrade Required'),
658 \Psr\Log\LogLevel
::ALERT
,
663 // if db.ver > code.ver, sth really wrong
664 if (version_compare($dbVersion, $codeVersion) > 0) {
665 $messages[] = new CRM_Utils_Check_Message(
667 ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state.
668 You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase
669 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.',
670 array(1 => $dbVersion, 2 => $codeVersion)
672 ts('Database In Unexpected Version'),
673 \Psr\Log\LogLevel
::ERROR
,
683 * ensure that all CiviCRM tables are InnoDB
686 public function checkDbEngine() {
689 if (CRM_Core_DAO
::isDBMyISAM(150)) {
690 $messages[] = new CRM_Utils_Check_Message(
692 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.'),
693 ts('MyISAM Database Engine'),
694 \Psr\Log\LogLevel
::ERROR
,