202 lines
6.4 KiB
PHP
202 lines
6.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file classes/site/VersionCheck.php
|
|
*
|
|
* Copyright (c) 2014-2021 Simon Fraser University
|
|
* Copyright (c) 2000-2021 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class VersionCheck
|
|
*
|
|
* @ingroup site
|
|
*
|
|
* @see Version
|
|
*
|
|
* @brief Provides methods to check for the latest version of the application.
|
|
*/
|
|
|
|
namespace PKP\site;
|
|
|
|
use APP\core\Application;
|
|
use DateInterval;
|
|
use Exception;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use PKP\config\Config;
|
|
use PKP\core\PKPString;
|
|
use PKP\db\DAORegistry;
|
|
use PKP\file\FileManager;
|
|
use SimpleXMLElement;
|
|
|
|
class VersionCheck
|
|
{
|
|
/** Max lifetime for the version cache */
|
|
protected const MAX_CACHE_LIFETIME = '1 year';
|
|
|
|
public const VERSION_CODE_PATH = 'dbscripts/xml/version.xml';
|
|
|
|
/**
|
|
* Return information about the latest available version.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getLatestVersion()
|
|
{
|
|
$application = Application::get();
|
|
$includeId = Application::isInstalled() &&
|
|
!Application::isUpgrading() &&
|
|
Config::getVar('general', 'enable_beacon', true);
|
|
|
|
if ($includeId) {
|
|
$uniqueSiteId = Application::get()->getUUID();
|
|
} else {
|
|
$uniqueSiteId = null;
|
|
}
|
|
|
|
$request = $application->getRequest();
|
|
return self::parseVersionXML(
|
|
$application->getVersionDescriptorUrl() .
|
|
($includeId ? '?id=' . urlencode($uniqueSiteId) .
|
|
'&oai=' . urlencode($request->url('index', 'oai'))
|
|
: '')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Return the currently installed database version.
|
|
*
|
|
* @return Version
|
|
*/
|
|
public static function getCurrentDBVersion()
|
|
{
|
|
$versionDao = DAORegistry::getDAO('VersionDAO'); /** @var VersionDAO $versionDao */
|
|
return $versionDao->getCurrentVersion();
|
|
}
|
|
|
|
/**
|
|
* Return the current code version.
|
|
*/
|
|
public static function getCurrentCodeVersion(): ?Version
|
|
{
|
|
return self::parseVersionXML(self::VERSION_CODE_PATH)['version'] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Parse information from a version XML file.
|
|
*/
|
|
public static function parseVersionXML(string $path): ?array
|
|
{
|
|
$isVirtual = FileManager::isVirtualPath($path);
|
|
$key = __METHOD__ . static::MAX_CACHE_LIFETIME . $path . ($isVirtual ? '' : filemtime($path));
|
|
$expiration = $isVirtual ? 0 : DateInterval::createFromDateString(static::MAX_CACHE_LIFETIME);
|
|
$version = Cache::remember($key, $expiration, function () use ($path) {
|
|
$xml = new SimpleXMLElement(FileManager::getStream($path));
|
|
$version = [];
|
|
foreach (['application', 'class', 'type', 'release', 'tag', 'date', 'info', 'package', 'lazy-load', 'sitewide'] as $name) {
|
|
if (isset($xml->$name)) {
|
|
$version[$name] = (string) $xml->$name;
|
|
}
|
|
}
|
|
$version['sitewide'] = (int) ($version['sitewide'] ?? 0);
|
|
$version['lazy-load'] = (int) ($version['lazy-load'] ?? 0);
|
|
if (isset($xml->patch)) {
|
|
$version['patch'] = [];
|
|
foreach ($xml->patch as $patch) {
|
|
$version['patch'][$patch['from']] = (string) $patch;
|
|
}
|
|
}
|
|
return $version;
|
|
});
|
|
|
|
// Built outside of the cache section to avoid serializing the Version (which would need a __set_state implementation)
|
|
if (isset($version['release']) && isset($version['application'])) {
|
|
$version['version'] = Version::fromString(
|
|
$version['release'] ?? '',
|
|
$version['type'] ?? '',
|
|
$version['application'] ?? '',
|
|
$version['class'] ?? '',
|
|
$version['lazy-load'],
|
|
$version['sitewide']
|
|
);
|
|
}
|
|
return $version;
|
|
}
|
|
|
|
/**
|
|
* Find the applicable patch for the current code version (if available).
|
|
*
|
|
* @param array $versionInfo as returned by parseVersionXML()
|
|
* @param Version $codeVersion as returned by getCurrentCodeVersion()
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getPatch($versionInfo, $codeVersion = null)
|
|
{
|
|
if (!isset($codeVersion)) {
|
|
$codeVersion = self::getCurrentCodeVersion();
|
|
}
|
|
if (isset($versionInfo['patch'][$codeVersion->getVersionString()])) {
|
|
return $versionInfo['patch'][$codeVersion->getVersionString()];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the given version file exists and whether it
|
|
* contains valid data. Returns a Version object if everything
|
|
* is ok, otherwise throws an Exception.
|
|
*
|
|
* @param string $versionFile
|
|
*
|
|
* @return Version
|
|
*/
|
|
public static function getValidPluginVersionInfo($versionFile)
|
|
{
|
|
$fileManager = new FileManager();
|
|
if ($fileManager->fileExists($versionFile)) {
|
|
$versionInfo = self::parseVersionXML($versionFile);
|
|
} else {
|
|
throw new Exception(__('manager.plugins.versionFileNotFound'));
|
|
}
|
|
|
|
// Validate plugin name and type to avoid abuse
|
|
$productType = explode('.', $versionInfo['type']);
|
|
if (count($productType) != 2 || $productType[0] != 'plugins') {
|
|
throw new Exception(__('manager.plugins.versionFileInvalid'));
|
|
}
|
|
|
|
$pluginVersion = $versionInfo['version'];
|
|
$namesToValidate = [$pluginVersion->getProduct(), $productType[1]];
|
|
foreach ($namesToValidate as $nameToValidate) {
|
|
if (!PKPString::regexp_match('/[a-z][a-zA-Z0-9]+/', $nameToValidate)) {
|
|
throw new Exception(__('manager.plugins.versionFileInvalid'));
|
|
}
|
|
}
|
|
|
|
return $pluginVersion;
|
|
}
|
|
|
|
/**
|
|
* Checks the application's version against the latest version
|
|
* on the PKP servers.
|
|
*
|
|
* @return string|false Version description or false if no newer version
|
|
*/
|
|
public static function checkIfNewVersionExists()
|
|
{
|
|
$versionInfo = self::getLatestVersion();
|
|
$latestVersion = $versionInfo['release'];
|
|
|
|
$currentVersion = self::getCurrentDBVersion();
|
|
if ($currentVersion->compare($latestVersion) < 0) {
|
|
return $latestVersion;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!PKP_STRICT_MODE) {
|
|
class_alias('\PKP\site\VersionCheck', '\VersionCheck');
|
|
define('VERSION_CODE_PATH', VersionCheck::VERSION_CODE_PATH);
|
|
}
|