timer('check_' . __CLASS__, self::CHECK_TIMER)) { // Best attempt at re-securing folders $config = CRM_Core_Config::singleton(); $config->cleanup(0, FALSE); if ($messages === NULL) { $messages = $this->checkAll(); } $statusMessages = array(); $statusType = 'alert'; foreach ($messages as $message) { if ($filter === TRUE || $message->getSeverity() >= 3) { $statusType = $message->getSeverity() >= 4 ? 'error' : $statusType; $statusMessage = $message->getMessage(); $statusMessages[] = $statusTitle = $message->getTitle(); } } if (count($statusMessages)) { if (count($statusMessages) > 1) { $statusTitle = ts('Multiple Alerts'); $statusMessage = ts('Please check your status page for a full list and further details.', array(1 => CRM_Utils_System::url('civicrm/a/#/status'))) . ''; } // @todo add link to status page CRM_Core_Session::setStatus($statusMessage, $statusTitle, $statusType); } } } } /** * Sort messages based upon severity * * @param CRM_Utils_Check_Message $a * @param CRM_Utils_Check_Message $b * @return int */ public static function severitySort($a, $b) { $aSeverity = $a->getSeverity(); $bSeverity = $b->getSeverity(); if ($aSeverity == $bSeverity) { return strcmp($a->getName(), $b->getName()); } // The Message constructor guarantees that these will always be integers. return ($aSeverity < $bSeverity); } /** * Get the integer value (useful for thresholds) of the severity. * * @param int|const $severity * the value to look up * @param bool $reverse * whether to find the constant from the integer * @return bool */ public static function severityMap($severity, $reverse = FALSE) { // Lowercase string-based severities if (!$reverse) { $severity = strtolower($severity); } // See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md $levels = array( \Psr\Log\LogLevel::EMERGENCY => 7, \Psr\Log\LogLevel::ALERT => 6, \Psr\Log\LogLevel::CRITICAL => 5, \Psr\Log\LogLevel::ERROR => 4, \Psr\Log\LogLevel::WARNING => 3, \Psr\Log\LogLevel::NOTICE => 2, \Psr\Log\LogLevel::INFO => 1, \Psr\Log\LogLevel::DEBUG => 0, ); return ($reverse) ? array_search($severity, $levels) : $levels[$severity]; } /** * Throw an exception if any of the checks fail. * * @param array|NULL $messages list of CRM_Utils_Check_Message; or NULL if the default list should be fetched * * @throws Exception */ public function assertValid($messages = NULL) { if ($messages === NULL) { $messages = $this->checkAll(); } if (!empty($messages)) { $messagesAsArray = array(); foreach ($messages as $message) { $messagesAsArray[] = $message->toArray(); } throw new Exception('There are configuration problems with this installation: ' . print_r($messagesAsArray, TRUE)); } } /** * Run some sanity checks. * * This could become a hook so that CiviCRM can run both built-in * configuration & sanity checks, and modules/extensions can add * their own checks. * * We might even expose the results of these checks on the Wordpress * plugin status page or the Drupal admin/reports/status path. * * @param bool $max * Whether to return just the maximum non-hushed severity * * @return array * Array of messages * @link https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_requirements */ public static function checkAll($max = FALSE) { $checks = array(); $checks[] = new CRM_Utils_Check_Security(); $checks[] = new CRM_Utils_Check_Env(); $compInfo = CRM_Core_Component::getEnabledComponents(); foreach ($compInfo as $compObj) { switch ($compObj->info['name']) { case 'CiviCase': $checks[] = new CRM_Utils_Check_Case(CRM_Case_XMLRepository::singleton(), CRM_Case_PseudoConstant::caseType('name')); break; default: } } $messages = array(); foreach ($checks as $check) { $messages = array_merge($messages, $check->checkAll()); } CRM_Utils_Hook::check($messages); foreach ($messages as $key => $message) { $hush = self::checkHushSnooze($message); $message->setVisible(!$hush); } uasort($messages, array(__CLASS__, 'severitySort')); $maxSeverity = 1; foreach ($messages as $message) { if (!$message->isVisible()) { continue; } $maxSeverity = max(1, $message->getLevel()); break; } Civi::cache()->set('systemCheckSeverity', $maxSeverity); $timestamp = time(); Civi::cache()->set('systemCheckDate', $timestamp); return ($max) ? $maxSeverity : $messages; } /** * Evaluate if a system check should be hushed/snoozed. * * @param string $message * * @return bool * TRUE means hush/snooze, FALSE means display. * @throws \CiviCRM_API3_Exception */ public static function checkHushSnooze($message) { $statusPreferenceParams = array( 'name' => $message->getName(), 'domain_id' => CRM_Core_Config::domainID(), ); // Check if there's a StatusPreference matching this name/domain. $statusPreference = civicrm_api3('StatusPreference', 'get', $statusPreferenceParams); $spid = FALSE; if (isset($statusPreference['id'])) { $spid = $statusPreference['id']; } if ($spid) { // If so, compare severity to StatusPreference->severity. $severity = $message->getSeverity(); if ($severity <= $statusPreference['values'][$spid]['ignore_severity']) { // A hush or a snooze has been set. Find out which. if (isset($statusPreference['values'][$spid]['hush_until'])) { // Snooze is set. $today = new DateTime(); $snoozeDate = new DateTime($statusPreference['values'][$spid]['hush_until']); if ($today > $snoozeDate) { // Snooze is expired. return FALSE; } else { // Snooze is active. return TRUE; } } else { // Hush. return TRUE; } } } return FALSE; } }