uploadDir
CACHEFILE_NAME = 'latest-version-cache.txt',
// cachefile expiry time (in seconds) - one day
CACHEFILE_EXPIRE = 86400;
/**
* We only need one instance of this object, so we use the
* singleton pattern and cache the instance in this variable
*
* @var object
* @static
*/
static private $_singleton = NULL;
/**
* The version of the current (local) installation
*
* @var string
*/
public $localVersion = NULL;
/**
* The latest version of CiviCRM
*
* @var string
*/
public $latestVersion = NULL;
/**
* Pingback params
*
* @var string
*/
protected $stats = array();
/**
* Class constructor
*
* @access private
*/
function __construct() {
global $civicrm_root;
$config = CRM_Core_Config::singleton();
$localfile = $civicrm_root . DIRECTORY_SEPARATOR . self::LOCALFILE_NAME;
$cachefile = $config->uploadDir . self::CACHEFILE_NAME;
if (file_exists($localfile)) {
require_once ($localfile);
if (function_exists('civicrmVersion')) {
$info = civicrmVersion();
$this->localVersion = trim($info['version']);
}
}
if ($config->versionCheck) {
$expiryTime = time() - self::CACHEFILE_EXPIRE;
// if there's a cachefile and it's not stale use it to
// read the latestVersion, else read it from the Internet
if (file_exists($cachefile) && (filemtime($cachefile) > $expiryTime)) {
$this->latestVersion = trim(file_get_contents($cachefile));
}
else {
$siteKey = md5(defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : '');
$this->stats = array(
'hash' => md5($siteKey . $config->userFrameworkBaseURL),
'version' => $this->localVersion,
'uf' => $config->userFramework,
'lang' => $config->lcMessages,
'co' => $config->defaultContactCountry,
'ufv' => $config->userFrameworkVersion,
'PHP' => phpversion(),
'MySQL' => CRM_CORE_DAO::singleValueQuery('SELECT VERSION()'),
'communityMessagesUrl' => CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'communityMessagesUrl', NULL, '*default*'),
);
// Add usage stats
$this->payProcStats();
$this->entityStats();
$this->extensionStats();
// Get the latest version and send site info
$this->pingBack();
// Update cache file
if ($this->latestVersion) {
$fp = @fopen($cachefile, 'w');
if (!$fp) {
if (CRM_Core_Permission::check('administer CiviCRM')) {
CRM_Core_Session::setStatus(
ts('Unable to write file') . ":$cachefile
" . ts('Please check your system file permissions.'),
ts('File Error'), 'error');
}
return;
}
fwrite($fp, $this->latestVersion);
fclose($fp);
}
}
}
}
/**
* Static instance provider
*
* Method providing static instance of CRM_Utils_VersionCheck,
* as in Singleton pattern
*
* @return CRM_Utils_VersionCheck
*/
static function &singleton() {
if (!isset(self::$_singleton)) {
self::$_singleton = new CRM_Utils_VersionCheck();
}
return self::$_singleton;
}
/**
* Get the latest version number if it's newer than the local one
*
* @return string|null
* Returns the newer version's number, or null if the versions are equal
*/
public function newerVersion() {
if ($this->latestVersion) {
if ((version_compare($this->localVersion, $this->latestVersion) < 0)
&& CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'versionAlert', NULL, TRUE)) {
return $this->latestVersion;
}
}
return NULL;
}
/**
* Alert the site admin of new versions of CiviCRM
* Show the message once a day
*/
public function versionAlert() {
if (CRM_Core_Permission::check('administer CiviCRM') && $this->newerVersion()
&& CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'versionAlert', NULL, TRUE)) {
$session = CRM_Core_Session::singleton();
if ($session->timer('version_alert', 24 * 60 * 60)) {
$msg = ts('A newer version of CiviCRM is available: %1', array(1 => $this->latestVersion))
. '
' . ts('Download Now', array(1 => 'http://civicrm.org/download'));
$session->setStatus($msg, ts('Update Available'));
}
}
}
/**
* Get active payment processor types
*/
private function payProcStats() {
$dao = new CRM_Financial_DAO_PaymentProcessor;
$dao->is_active = 1;
$dao->find();
$ppTypes = array();
// Get title and id for all processor types
$ppTypeNames = CRM_Core_PseudoConstant::paymentProcessorType();
while ($dao->fetch()) {
$ppTypes[] = $ppTypeNames[$dao->payment_processor_type_id];
}
// add the .-separated list of the processor types
$this->stats['PPTypes'] = implode(',', array_unique($ppTypes));
}
/**
* Fetch counts from entity tables
* Add info to the 'entities' array
*/
private function entityStats() {
$tables = array(
'CRM_Activity_DAO_Activity' => 'is_test = 0',
'CRM_Case_DAO_Case' => 'is_deleted = 0',
'CRM_Contact_DAO_Contact' => 'is_deleted = 0',
'CRM_Contact_DAO_Relationship' => NULL,
'CRM_Campaign_DAO_Campaign' => NULL,
'CRM_Contribute_DAO_Contribution' => 'is_test = 0',
'CRM_Contribute_DAO_ContributionPage' => 'is_active = 1',
'CRM_Contribute_DAO_ContributionProduct' => NULL,
'CRM_Contribute_DAO_Widget' => 'is_active = 1',
'CRM_Core_DAO_Discount' => NULL,
'CRM_Price_DAO_PriceSetEntity' => NULL,
'CRM_Core_DAO_UFGroup' => 'is_active = 1',
'CRM_Event_DAO_Event' => 'is_active = 1',
'CRM_Event_DAO_Participant' => 'is_test = 0',
'CRM_Friend_DAO_Friend' => 'is_active = 1',
'CRM_Grant_DAO_Grant' => NULL,
'CRM_Mailing_DAO_Mailing' => 'is_completed = 1',
'CRM_Member_DAO_Membership' => 'is_test = 0',
'CRM_Member_DAO_MembershipBlock' => 'is_active = 1',
'CRM_Pledge_DAO_Pledge' => 'is_test = 0',
'CRM_Pledge_DAO_PledgeBlock' => NULL,
);
foreach ($tables as $daoName => $where) {
$dao = new $daoName;
if ($where) {
$dao->whereAdd($where);
}
$short_name = substr($daoName, strrpos($daoName, '_') + 1);
$this->stats['entities'][] = array(
'name' => $short_name,
'size' => $dao->count(),
);
}
}
/**
* Fetch stats about enabled components/extensions
* Add info to the 'extensions' array
*/
private function extensionStats() {
// Core components
$config = CRM_Core_Config::singleton();
foreach ($config->enableComponents as $comp) {
$this->stats['extensions'][] = array(
'name' => 'org.civicrm.component.' . strtolower($comp),
'enabled' => 1,
'version' => $this->stats['version'],
);
}
// Contrib extensions
$mapper = CRM_Extension_System::singleton()->getMapper();
$dao = new CRM_Core_DAO_Extension();
$dao->find();
while ($dao->fetch()) {
$info = $mapper->keyToInfo($dao->full_name);
$this->stats['extensions'][] = array(
'name' => $dao->full_name,
'enabled' => $dao->is_active,
'version' => isset($info->version) ? $info->version : NULL,
);
}
}
/**
* Send the request to civicrm.org
* Set timeout and suppress errors
*/
private function pingBack() {
ini_set('default_socket_timeout', self::CHECK_TIMEOUT);
$params = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($this->stats),
),
);
$ctx = stream_context_create($params);
$this->latestVersion = @file_get_contents(self::LATEST_VERSION_AT, FALSE, $ctx);
if (!preg_match('/^\d+\.\d+\.\d+$/', $this->latestVersion)) {
$this->latestVersion = NULL;
}
else {
$this->latestVersion = trim($this->latestVersion);
}
ini_restore('default_socket_timeout');
}
}