*/
class CRM_Utils_VersionCheck {
const
- PINGBACK_URL = 'http://latest.civicrm.org/stable.php?format=json',
- // relative to $civicrm_root
- LOCALFILE_NAME = '[civicrm.root]/civicrm-version.php',
- // relative to $config->uploadDir
- CACHEFILE_NAME = '[civicrm.files]/persist/version-info-cache.json';
+ CACHEFILE_NAME = 'version-info-cache.json',
+ // after this length of time we fall back on poor-man's cron (7+ days)
+ CACHEFILE_EXPIRE = 605000;
/**
* The version of the current (local) installation
*/
public $isInfoAvailable;
+ /**
+ * @var array
+ */
+ public $cronJob = array();
+
+ /**
+ * @var string
+ */
+ public $pingbackUrl = 'http://latest.civicrm.org/stable.php?format=json';
+
/**
* Pingback params
*
*
* @var string
*/
- protected $cacheFile;
+ public $cacheFile;
/**
* Class constructor.
*/
public function __construct() {
- // Populate local version
- $localFile = Civi::paths()->getPath(self::LOCALFILE_NAME);
- if (file_exists($localFile)) {
- require_once $localFile;
- }
- if (function_exists('civicrmVersion')) {
- $info = civicrmVersion();
- $this->localVersion = trim($info['version']);
- $this->localMajorVersion = $this->getMajorVersion($this->localVersion);
- }
+ $this->localVersion = CRM_Utils_System::version();
+ $this->localMajorVersion = $this->getMajorVersion($this->localVersion);
+ $this->cacheFile = CRM_Core_Config::singleton()->uploadDir . self::CACHEFILE_NAME;
+ }
+
+ /**
+ * Self-populates version info
+ *
+ * @throws \Exception
+ */
+ public function initialize() {
+ $this->getJob();
// Populate remote $versionInfo from cache file
- $this->cacheFile = Civi::paths()->getPath(self::CACHEFILE_NAME);
$this->isInfoAvailable = $this->readCacheFile();
+
+ // Poor-man's cron fallback if scheduled job is enabled but has failed to run
+ $expiryTime = time() - self::CACHEFILE_EXPIRE;
+ if (!empty($this->cronJob['is_active']) &&
+ (!$this->isInfoAvailable || filemtime($this->cacheFile) < $expiryTime)
+ ) {
+ // First try updating the files modification time, for 2 reasons:
+ // - if the file is not writeable, this saves the trouble of pinging back
+ // - if the remote server is down, this will prevent an immediate retry
+ if (touch($this->cacheFile) === FALSE) {
+ throw new Exception('File not writable');
+ }
+ $this->fetch();
+ }
+ }
+
+ /**
+ * Sets $versionInfo
+ *
+ * @param $info
+ */
+ public function setVersionInfo($info) {
+ $this->versionInfo = (array) $info;
+ // Sort version info in ascending order for easier comparisons
+ ksort($this->versionInfo, SORT_NUMERIC);
}
/**
),
);
$ctx = stream_context_create($params);
- $rawJson = file_get_contents(self::PINGBACK_URL, FALSE, $ctx);
+ $rawJson = file_get_contents($this->pingbackUrl, FALSE, $ctx);
$versionInfo = $rawJson ? json_decode($rawJson, TRUE) : NULL;
// If we couldn't fetch or parse the data $versionInfo will be NULL
// Otherwise it will be an array and we'll cache it.
// Note the array may be empty e.g. in the case of a pre-alpha with no releases
- if ($versionInfo !== NULL) {
+ $this->isInfoAvailable = $versionInfo !== NULL;
+ if ($this->isInfoAvailable) {
$this->writeCacheFile($rawJson);
- $this->versionInfo = $versionInfo;
+ $this->setVersionInfo($versionInfo);
}
}
*/
private function readCacheFile() {
if (file_exists($this->cacheFile)) {
- $this->versionInfo = (array) json_decode(file_get_contents($this->cacheFile), TRUE);
- // Sort version info in ascending order for easier comparisons
- ksort($this->versionInfo, SORT_NUMERIC);
+ $this->setVersionInfo(json_decode(file_get_contents($this->cacheFile), TRUE));
return TRUE;
}
return FALSE;
/**
* Save version info to file.
* @param string $contents
+ * @throws \Exception
*/
private function writeCacheFile($contents) {
- $fp = fopen($this->cacheFile, 'w');
- fwrite($fp, $contents);
- fclose($fp);
+ if (file_put_contents($this->cacheFile, $contents) === FALSE) {
+ throw new Exception('File not writable');
+ }
+ }
+
+ /**
+ * Lookup version_check scheduled job
+ */
+ private function getJob() {
+ $jobs = civicrm_api3('Job', 'get', array(
+ 'sequential' => 1,
+ 'api_action' => "version_check",
+ 'api_entity' => "job",
+ ));
+ $this->cronJob = CRM_Utils_Array::value(0, $jobs['values'], array());
}
}