CRM-13283 misc sp acing problems
[civicrm-core.git] / CRM / Utils / Check / Env.php
CommitLineData
1e927c45
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
1e927c45 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
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
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
1e927c45
TO
32 * $Id: $
33 *
34 */
35class CRM_Utils_Check_Env {
36
37 /**
38 * Run some sanity checks.
39 *
40 * @return array<CRM_Utils_Check_Message>
41 */
42 public function checkAll() {
43 $messages = array_merge(
7342d7c4
TO
44 $this->checkMysqlTime(),
45 $this->checkDebug(),
1b366958
AH
46 $this->checkOutboundMail(),
47 $this->checkDomainNameEmail(),
aa96ce62 48 $this->checkDefaultMailbox(),
06576a03 49 $this->checkLastCron(),
580ad3ef
AH
50 $this->checkVersion(),
51 $this->checkExtensions(),
52 $this->checkExtensionUpgrades(),
53 $this->checkDbVersion(),
54 $this->checkDbEngine()
1e927c45
TO
55 );
56 return $messages;
57 }
58
7342d7c4
TO
59 /**
60 * Check that the MySQL time settings match the PHP time settings.
61 *
62 * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings
63 */
1e927c45
TO
64 public function checkMysqlTime() {
65 $messages = array();
66
67 $phpNow = date('Y-m-d H:i');
68 $sqlNow = CRM_Core_DAO::singleValueQuery("SELECT date_format(now(), '%Y-%m-%d %H:%i')");
8010540a 69 if (!CRM_Utils_Time::isEqual($phpNow, $sqlNow, 2.5 * 60)) {
1e927c45
TO
70 $messages[] = new CRM_Utils_Check_Message(
71 'checkMysqlTime',
72 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 73 1 => CRM_Utils_System::getWikiBaseURL() . 'checkMysqlTime',
1e927c45
TO
74 2 => $sqlNow,
75 3 => $phpNow,
76 )),
1b366958 77 ts('Timestamp Mismatch'),
7df9b5d5 78 \Psr\Log\LogLevel::ERROR
1e927c45
TO
79 );
80 }
81
82 return $messages;
83 }
7342d7c4 84
5bc392e6
EM
85 /**
86 * @return array
87 */
7342d7c4
TO
88 public function checkDebug() {
89 $messages = array();
90
91 $config = CRM_Core_Config::singleton();
92 if ($config->debug) {
93 $messages[] = new CRM_Utils_Check_Message(
94 'checkDebug',
95 ts('Warning: Debug is enabled in <a href="%1">system settings</a>. This should not be enabled on production servers.',
96 array(1 => CRM_Utils_System::url('civicrm/admin/setting/debug', 'reset=1'))),
1b366958 97 ts('Debug Mode Enabled'),
7df9b5d5 98 \Psr\Log\LogLevel::WARNING
7342d7c4
TO
99 );
100 }
101
102 return $messages;
103 }
104
5bc392e6
EM
105 /**
106 * @return array
107 */
7342d7c4
TO
108 public function checkOutboundMail() {
109 $messages = array();
110
111 $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'mailing_backend');
112 if (($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB
113 || (defined('CIVICRM_MAIL_LOG') && CIVICRM_MAIL_LOG)
114 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED
115 || $mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MOCK)
116 ) {
117 $messages[] = new CRM_Utils_Check_Message(
118 'checkOutboundMail',
119 ts('Warning: Outbound email is disabled in <a href="%1">system settings</a>. Proper settings should be enabled on production servers.',
120 array(1 => CRM_Utils_System::url('civicrm/admin/setting/smtp', 'reset=1'))),
1b366958 121 ts('Outbound Email Disabled'),
7df9b5d5 122 \Psr\Log\LogLevel::WARNING
7342d7c4
TO
123 );
124 }
125
126 return $messages;
127 }
96025800 128
1b366958
AH
129 /**
130 * Check that domain email and org name are set
131 * @return array
132 */
1b366958
AH
133 public function checkDomainNameEmail() {
134 $messages = array();
135
136 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(TRUE);
137 $domain = CRM_Core_BAO_Domain::getDomain();
138 $domainName = $domain->name;
139 $fixEmailUrl = CRM_Utils_System::url("civicrm/admin/domain", "action=update&reset=1");
140
141 if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
142 if (!$domainName || $domainName == 'Default Domain Name') {
143 $msg = ts("Please enter your organization's <a href=\"%1\">name, primary address, and default FROM Email Address</a> (for system-generated emails).",
144 array(1 => $fixEmailUrl));
145 }
146 else {
147 $msg = ts('Please enter a <a href="%1">default FROM Email Address</a> (for system-generated emails).',
148 array(1 => $fixEmailUrl));
149 }
150 }
151 elseif (!$domainName || $domainName == 'Default Domain Name') {
152 $msg = ts("Please enter your organization's <a href=\"%1\">name and primary address</a>.",
153 array(1 => $fixEmailUrl));
154 }
aacaa119
AH
155
156 if (!empty($msg)) {
157 $messages[] = new CRM_Utils_Check_Message(
158 'checkDomainNameEmail',
159 $msg,
160 ts('Complete Setup'),
161 \Psr\Log\LogLevel::WARNING
162 );
163 }
1b366958
AH
164
165 return $messages;
166 }
167
168 /**
169 * Checks if a default bounce handling mailbox is set up
170 * @return array
171 */
1b366958
AH
172 public function checkDefaultMailbox() {
173 $messages = array();
174 $config = CRM_Core_Config::singleton();
175
176 if (in_array('CiviMail', $config->enableComponents) &&
177 CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG"
178 ) {
179 $message = new CRM_Utils_Check_Message(
180 'checkDefaultMailbox',
aa96ce62 181 ts('Please configure a <a href="%1">default mailbox</a> for CiviMail.',
1b366958
AH
182 array(1 => CRM_Utils_System::url('civicrm/admin/mailSettings', "reset=1"))),
183 ts('Configure Default Mailbox'),
184 \Psr\Log\LogLevel::WARNING
185 );
186 $message->addHelp(ts('Learn more in the <a href="%1">user guide</a>', array(1 => 'http://book.civicrm.org/user/advanced-configuration/email-system-configuration/')));
187 $messages[] = $message;
188 }
189
190 return $messages;
191 }
aa96ce62
AH
192
193 /**
194 * Checks if cron has run in a reasonable amount of time
195 * @return array
196 */
aa96ce62
AH
197 public function checkLastCron() {
198 $messages = array();
199
200 $statusPreference = new CRM_Core_DAO_StatusPreference();
201 $statusPreference->domain_id = CRM_Core_Config::domainID();
202 $statusPreference->name = 'checkLastCron';
203
fba5f6ac
AH
204 if ($statusPreference->find(TRUE)) {
205 $lastCron = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StatusPreference', $statusPreference->id, 'check_info');
206 $msg = ts('Last cron run at %1.', array(1 => CRM_Utils_Date::customFormat(date('c', $lastCron))));
207 }
208 else {
209 $lastCron = 0;
210 $msg = ts('No cron runs have been recorded.');
211 }
aa96ce62 212
aa96ce62
AH
213 if ($lastCron > gmdate('U') - 3600) {
214 $messages[] = new CRM_Utils_Check_Message(
215 'checkLastCron',
216 $msg,
217 ts('Cron Running OK'),
218 \Psr\Log\LogLevel::INFO
219 );
220 }
221 elseif ($lastCron > gmdate('U') - 86400) {
222 $message = new CRM_Utils_Check_Message(
223 'checkLastCron',
224 $msg,
225 ts('Cron Not Running'),
226 \Psr\Log\LogLevel::WARNING
227 );
06576a03 228 $message->addHelp(ts('Learn more in the <a href="%1">Administrator\'s Guide supplement</a>', array(1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Managing+Scheduled+Jobs')));
aa96ce62
AH
229 $messages[] = $message;
230 }
fba5f6ac 231 else {
aa96ce62
AH
232 $message = new CRM_Utils_Check_Message(
233 'checkLastCron',
234 $msg,
235 ts('Cron Not Running'),
236 \Psr\Log\LogLevel::ERROR
237 );
06576a03 238 $message->addHelp(ts('Learn more in the <a href="%1">Administrator\'s Guide supplement</a>', array(1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Managing+Scheduled+Jobs')));
aa96ce62
AH
239 $messages[] = $message;
240 }
241
242 return $messages;
243 }
fba5f6ac
AH
244
245 /**
246 * Checks if new versions are available
247 * @return array
248 */
fba5f6ac
AH
249 public function checkVersion() {
250 $messages = array();
251
06576a03 252 if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'versionAlert', NULL, 1)) {
097c681e 253 $vc = CRM_Utils_VersionCheck::singleton();
06576a03
AH
254 $newerVersion = $vc->isNewerVersionAvailable();
255
256 if ($newerVersion['version']) {
257 $vInfo = array(
258 1 => $newerVersion['version'],
259 2 => $vc->localVersion,
260 );
261 if ($newerVersion['status'] == 'lts') {
262 $vInfo[1] .= ' ' . ts('(long-term support)'); // LTS = long-term support version
263 }
264
265 if ($newerVersion['upgrade'] == 'security') {
266 // For most new versions, just make them notice
267 $severity = \Psr\Log\LogLevel::CRITICAL;
268 $message = ts('New security release %1 is available. The site is currently running %2.', $vInfo);
269 }
270 elseif ($newerVersion['status'] == 'eol') {
271 // Warn about EOL
272 $severity = \Psr\Log\LogLevel::WARNING;
273 $message = ts('New version %1 is available. The site is currently running %2, which has reached its end of life.', $vInfo);
274 }
275 else {
276 // For most new versions, just make them notice
277 $severity = \Psr\Log\LogLevel::NOTICE;
278 $message = ts('New version %1 is available. The site is currently running %2.', $vInfo);
279 }
280 }
281 else {
282 $vNum = $vc->localVersion;
283 if ($newerVersion['status'] == 'lts') {
284 $vNum .= ' ' . ts('(long-term support)'); // LTS = long-term support version
285 }
fba5f6ac 286
06576a03
AH
287 $severity = \Psr\Log\LogLevel::INFO;
288 $message = ts('Version %1 is up-to-date.', array(1 => $vNum));
289 }
fba5f6ac 290
06576a03
AH
291 $messages[] = new CRM_Utils_Check_Message(
292 'checkVersion',
293 $message,
294 ts('Update Status'),
295 $severity
296 );
297 }
298 else {
299 $messages[] = new CRM_Utils_Check_Message(
300 'checkVersion',
301 ts('The check for new versions of CiviCRM has been disabled.'),
302 ts('Update Check Disabled'),
303 \Psr\Log\LogLevel::NOTICE
304 );
305 }
fba5f6ac 306
06576a03 307 return $messages;
fba5f6ac 308 }
580ad3ef
AH
309
310 /**
311 * Checks if extensions are set up properly
312 * @return array
313 */
580ad3ef
AH
314 public function checkExtensions() {
315 $messages = array();
316 $extensionSystem = CRM_Extension_System::singleton();
317 $mapper = $extensionSystem->getMapper();
318 $manager = $extensionSystem->getManager();
319 $remotes = $extensionSystem->getBrowser()->getExtensions();
320
321 if ($extensionSystem->getDefaultContainer()) {
322 $basedir = $extensionSystem->getDefaultContainer()->baseDir;
323 }
324
325 if (empty($basedir)) {
326 // no extension directory
327 $messages[] = new CRM_Utils_Check_Message(
328 'checkExtensions',
329 ts('Your extensions directory is not set. Click <a href="%1">here</a> to set the extensions directory.',
330 array(1 => CRM_Utils_System::url('civicrm/admin/setting/path', 'reset=1'))),
331 ts('Extensions directory not writable'),
332 \Psr\Log\LogLevel::NOTICE
333 );
334 return $messages;
335 }
336
337 if (!is_dir($basedir)) {
338 $messages[] = new CRM_Utils_Check_Message(
339 'checkExtensions',
9329d168
AH
340 ts('Your extensions directory path points to %1, which is not a directory. Please check your file system.',
341 array(1 => $basedir)),
580ad3ef
AH
342 ts('Extensions directory incorrect'),
343 \Psr\Log\LogLevel::ERROR
344 );
345 return $messages;
346 }
347 elseif (!is_writable($basedir)) {
348 $messages[] = new CRM_Utils_Check_Message(
349 'checkExtensions',
9329d168
AH
350 ts('Your extensions directory, %1, is not writable. Please change your file permissions.',
351 array(1 => $basedir)),
580ad3ef
AH
352 ts('Extensions directory not writable'),
353 \Psr\Log\LogLevel::ERROR
354 );
355 return $messages;
356 }
357
358 if (empty($extensionSystem->getDefaultContainer()->baseUrl)) {
359 $messages[] = new CRM_Utils_Check_Message(
360 'checkExtensions',
361 ts('The extensions URL is not properly set. Please go to the <a href="%1">URL setting page</a> and correct it.',
362 array(1 => CRM_Utils_System::url('civicrm/admin/setting/url', 'reset=1'))),
363 ts('Extensions directory not writable'),
364 \Psr\Log\LogLevel::ERROR
365 );
366 return $messages;
367 }
368
369 $keys = array_keys($manager->getStatuses());
370 sort($keys);
371 $severity = 1;
372 $msgArray = $okextensions = array();
373 foreach ($keys as $key) {
374 try {
375 $obj = $mapper->keyToInfo($key);
376 }
377 catch (CRM_Extension_Exception $ex) {
378 $severity = 4;
379 $msgArray[] = ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key));
380 continue;
381 }
382 $row = CRM_Admin_Page_Extensions::createExtendedInfo($obj);
383 switch ($row['status']) {
384 case CRM_Extension_Manager::STATUS_INSTALLED_MISSING:
385 $severity = 4;
386 $msgArray[] = ts('%1 extension (%2) is installed but missing files.', array(1 => CRM_Utils_Array::value('label', $row), 2 => $key));
387 break;
388
389 case CRM_Extension_Manager::STATUS_INSTALLED:
390 if (CRM_Utils_Array::value($key, $remotes)) {
391 if (version_compare($row['version'], $remotes[$key]->version, '<')) {
392 $severity = ($severity < 3) ? 3 : $severity;
393 $msgArray[] = ts('%1 extension (%2) is upgradeable to version %3.', array(1 => CRM_Utils_Array::value('label', $row), 2 => $key, 3 => $remotes[$key]->version));
394 }
395 else {
396 $okextensions[] = CRM_Utils_Array::value('label', $row) ? "{$row['label']} ($key)" : $key;
397 }
398 }
399 else {
400 $okextensions[] = CRM_Utils_Array::value('label', $row) ? "{$row['label']} ($key)" : $key;
401 }
402 break;
403
404 case CRM_Extension_Manager::STATUS_UNINSTALLED:
405 case CRM_Extension_Manager::STATUS_DISABLED:
406 case CRM_Extension_Manager::STATUS_DISABLED_MISSING:
407 default:
408 }
409 }
410 $msg = implode(' ', $msgArray);
411 if (empty($msgArray)) {
412 $msg = (empty($okextensions)) ? ts('No extensions installed.') : ts('Extensions are up-to-date:') . ' ' . implode(', ', $okextensions);
413 }
414 elseif (!empty($okextensions)) {
415 $msg .= ' ' . ts('Other extensions are up-to-date:') . ' ' . implode(', ', $okextensions);
416 }
097c681e
AH
417
418 // OK, return several data rows
419 $returnValues = array(
580ad3ef
AH
420 array('status' => $return, 'message' => $msg),
421 );
422
423 $messages[] = new CRM_Utils_Check_Message(
424 'checkExtensions',
425 $msg,
426 ts('Extension Updates'),
427 CRM_Utils_Check::severityMap($severity, TRUE)
428 );
429
430 return $messages;
431 }
432
433
434 /**
435 * Checks if extensions are set up properly
436 * @return array
437 */
438 public function checkExtensionUpgrades() {
439 $messages = array();
440
441 if (CRM_Extension_Upgrades::hasPending()) {
442 $messages[] = new CRM_Utils_Check_Message(
443 'checkExtensionUpgrades',
444 ts('Extension upgrades are pending. Please visit <a href="%1">the upgrade page</a> to run them.',
445 array(1 => CRM_Utils_System::url('civicrm/admin/extensions/upgrade', 'reset=1'))),
446 ts('Run Extension Upgrades'),
447 \Psr\Log\LogLevel::ERROR
448 );
449 }
450 return $messages;
451 }
452
453 /**
454 * Checks if CiviCRM database version is up-to-date
455 * @return array
456 */
580ad3ef
AH
457 public function checkDbVersion() {
458 $messages = array();
459 $dbVersion = CRM_Core_BAO_Domain::version();
460 $upgradeUrl = CRM_Utils_System::url("civicrm/upgrade", "reset=1");
461
462 if (!$dbVersion) {
463 // if db.ver missing
464 $messages[] = new CRM_Utils_Check_Message(
465 'checkDbVersion',
466 ts('Version information found to be missing in database. You will need to determine the correct version corresponding to your current database state.'),
467 ts('Database Version Missing'),
468 \Psr\Log\LogLevel::ERROR
469 );
470 }
471 elseif (!CRM_Utils_System::isVersionFormatValid($dbVersion)) {
472 $messages[] = new CRM_Utils_Check_Message(
473 'checkDbVersion',
474 ts('Database is marked with invalid version format. You may want to investigate this before you proceed further.'),
475 ts('Database Version Invalid'),
476 \Psr\Log\LogLevel::ERROR
477 );
478 }
479 elseif (stripos($dbVersion, 'upgrade')) {
480 // if db.ver indicates a partially upgraded db
481 $messages[] = new CRM_Utils_Check_Message(
482 'checkDbVersion',
483 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)),
484 ts('Database Partially Upgraded'),
485 \Psr\Log\LogLevel::ALERT
486 );
487 }
488 else {
489 $codeVersion = CRM_Utils_System::version();
490
491 // if db.ver < code.ver, time to upgrade
492 if (version_compare($dbVersion, $codeVersion) < 0) {
493 $messages[] = new CRM_Utils_Check_Message(
494 'checkDbVersion',
495 ts('New codebase version detected. You must visit <a href=\'%1\'>upgrade screen</a> to upgrade the database.', array(1 => $upgradeUrl)),
496 ts('Database Upgrade Required'),
497 \Psr\Log\LogLevel::ALERT
498 );
499 }
500
501 // if db.ver > code.ver, sth really wrong
502 if (version_compare($dbVersion, $codeVersion) > 0) {
503 $messages[] = new CRM_Utils_Check_Message(
504 'checkDbVersion',
505 ts('Your database is marked with an unexpected version number: %1. The v%2 codebase may not be compatible with your database state.
506 You will need to determine the correct version corresponding to your current database state. You may want to revert to the codebase
507 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.',
508 array(1 => $dbVersion, 2 => $codeVersion)
509 ),
510 ts('Database In Unexpected Version'),
511 \Psr\Log\LogLevel::ERROR
512 );
513 }
514 }
515
516 return $messages;
517 }
518
519 /**
520 * ensure that all CiviCRM tables are InnoDB
521 * @return array
522 */
580ad3ef
AH
523 public function checkDbEngine() {
524 $messages = array();
525
526 if (CRM_Core_DAO::isDBMyISAM(150)) {
527 $messages[] = new CRM_Utils_Check_Message(
528 'checkDbEngine',
529 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.'),
530 ts('MyISAM Database Engine'),
531 \Psr\Log\LogLevel::ERROR
532 );
533 }
534 return $messages;
535 }
536
5bc392e6 537}