File: /var/www/apklausos/application/libraries/ExtensionInstaller/ExtensionUpdater.php
<?php
/**
* LimeSurvey
* Copyright (C) 2007-2015 The LimeSurvey Project Team / Carsten Schmitz
* All rights reserved.
* License: GNU/GPL License v2 or later, see LICENSE.php
* LimeSurvey is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/
namespace LimeSurvey\ExtensionInstaller;
use Exception;
use ExtensionConfig;
/**
* @since 2018-09-26
* @author LimeSurvey GmbH
*/
abstract class ExtensionUpdater
{
/**
* Extension model, e.g. Theme or Plugin class.
* @todo Create interface ExtensionModelInterface that all extension model classes implement
* @var mixed
*/
protected $model = null;
/**
* If true, fetch stable version info.
* @var boolean
*/
protected $useStable = true;
/**
* If true, fetch unstable version info.
* @var boolean
*/
protected $useUnstable = false;
/**
* @param mixed $model Plugin model, theme model, etc, depending on extension type.
*/
public function __construct($model)
{
$this->model = $model;
}
/**
* @return void
*/
public function setUseUnstable()
{
$this->useUnstable = true;
}
/**
* Returns true if $newVersion is strictly higher than currently installed version
*
* @param string $newVersion
* @return bool
*/
public function versionHigherThan($newVersion)
{
return version_compare($newVersion, $this->getCurrentVersion(), '>');
}
/**
* Returns true if $version is stable.
* The version is stable IF it does not contain
* alpha, beta or rc suffixes.
* @param string $version
* @return boolean
*/
public function versionIsStable($version)
{
if (empty($version)) {
return false;
}
$suffixes = [
'alpha',
'beta',
'rc',
];
$version = strtolower($version);
foreach ($suffixes as $suffix) {
if (strpos($version, $suffix) !== false) {
return false;
}
}
return true;
}
/**
* Returns true if $versions contain a security version.
* @param array $versions Each version has keys 'version' and 'isSecurityVersion'.
* @return boolean
*/
public function foundSecurityVersion(array $versions)
{
foreach ($versions as $version) {
if ($version['isSecurityVersion']) {
return true;
}
}
return false;
}
/**
* Implode $versions into string, stripping security version field.
* @param array $versions Each version has keys 'version' and 'isSecurityVersion'.
* @return string
*/
public function implodeVersions(array $versions)
{
$versions = array_map(
function ($version) {
return $version['version'];
},
$versions
);
return implode(', ', $versions);
}
/**
* Compose version message to display of $versions.
* @param array $versions Each version has keys 'version' and 'isSecurityVersion', etc.
* @return string
*/
public function getVersionMessage(array $versions)
{
$extensionName = $this->getExtensionName();
$extensionType = $this->getExtensionType();
if ($this->foundSecurityVersion($versions)) {
$message = '<b>' . gT('There are security updates available for %s (type: %s).', 'js') . '</b>';
} else {
$message = gT('There are updates available for %s (type: %s).', 'js');
}
$message = sprintf(
$message,
$extensionName,
$this->convertExtensionType($extensionType)
);
$latestVersion = $this->getLatestVersion($versions);
$message .= ' ' . sprintf(
gT('The latest available version is %s.', 'js'),
$latestVersion['version']
);
if (!empty($latestVersion['manualUpdateUrl'])) {
$message .= ' ' . sprintf(
gT('Please visit %s to download the update.', 'js'),
'<a href="' . $latestVersion['manualUpdateUrl'] . '">' . $latestVersion['manualUpdateUrl'] . '</a>'
);
}
return '<p>' . $message . '</p>';
}
/**
* @param array $versions
* @return array|null
*/
public function getLatestVersion(array $versions)
{
if (empty($versions)) {
return null;
}
$highestVersion = $versions[0];
foreach ($versions as $version) {
if (version_compare($version['version'], $highestVersion['version'], '>')) {
$highestVersion = $version;
}
}
return $highestVersion;
}
/**
* Fetch all new available version from each version fetcher.
* @return array $versions
* @todo Move to parent class?
*/
public function fetchVersions()
{
$config = $this->getExtensionConfig();
$versionFetchers = $config->createVersionFetchers();
if (empty($versionFetchers)) {
// No fetchers, can't fetch remote version.
return [];
}
$allowUnstable = getGlobalSetting('allow_unstable_extension_update');
$versions = [];
foreach ($versionFetchers as $fetcher) {
// Setup fetcher.
$fetcher->setExtensionName($this->getExtensionName());
$fetcher->setExtensionType($this->getExtensionType());
// Fetch versions.
$newVersion = $fetcher->getLatestVersion();
$lastSecurityVersion = $fetcher->getLatestSecurityVersion();
if (version_compare($lastSecurityVersion, $this->getCurrentVersion(), '>')) {
$versions[] = [
'isSecurityVersion' => true,
'version' => $lastSecurityVersion,
'manualUpdateUrl' => $fetcher->getManualUpdateUrl()
];
}
// If this version is unstable and we're not allowed to use it, continue.
if (!$allowUnstable && !$this->versionIsStable($newVersion)) {
continue;
}
if (version_compare($newVersion, $this->getCurrentVersion(), '>')) {
$versions[] = [
'isSecurityVersion' => false,
'version' => $newVersion,
'manualUpdateUrl' => $fetcher->getManualUpdateUrl()
];
} else {
// Ignore.
}
}
return $versions;
}
/**
* Convert from single char $type to fullword.
*
* @param string $type
* @return string
*/
public function convertExtensionType($type)
{
switch ($type) {
case 'p':
return gT('Plugin');
case 't':
return gT('Theme');
case 's':
return gT('Survey template');
case 'q':
return gT('Question template');
default:
throw new Exception();
}
}
/**
* Create an updater object for every extension of corresponding type.
* @return array [ExtensionUpdater[] $updaters, string[] $errorMessages]
*/
abstract public static function createUpdaters();
/**
* Fetch extension name from extension model.
* Extension type specific implementation.
* @return string
*/
abstract public function getExtensionName();
/**
* Fetch extension type from extension model.
* Extension type specific implementation.
* @return string
*/
abstract public function getExtensionType();
/**
* Get extension config object for this extension.
* @return ExtensionConfig
*/
abstract public function getExtensionConfig();
/**
* Returns currently installed version of this extension
* @return string
*/
abstract public function getCurrentVersion();
}