phpBB

Code Changes

File: phpbb/version_helper.php

  Unmodified   Added   Modified   Removed
Line 32Line 32
	 * @var string File name
*/
protected $file = 'versions.json';

	 * @var string File name
*/
protected $file = 'versions.json';

 

/**
* @var bool Use SSL or not
*/
protected $use_ssl = false;


/**
* @var string Current version installed


/**
* @var string Current version installed

Line 49Line 54

/** @var \phpbb\config\config */
protected $config;


/** @var \phpbb\config\config */
protected $config;

 

/** @var \phpbb\file_downloader */
protected $file_downloader;


/** @var \phpbb\user */
protected $user;


/** @var \phpbb\user */
protected $user;

 

protected $version_schema = array(
'stable' => array(
'current' => 'version',
'download' => 'url',
'announcement' => 'url',
'eol' => 'url',
'security' => 'bool',
),
'unstable' => array(
'current' => 'version',
'download' => 'url',
'announcement' => 'url',
'eol' => 'url',
'security' => 'bool',
),
);


/**
* Constructor
*
* @param \phpbb\cache\service $cache
* @param \phpbb\config\config $config


/**
* Constructor
*
* @param \phpbb\cache\service $cache
* @param \phpbb\config\config $config

 
	 * @param \phpbb\file_downloader $file_downloader

	 * @param \phpbb\user $user
*/

	 * @param \phpbb\user $user
*/

	public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\user $user)

	public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\user $user)

	{
$this->cache = $cache;
$this->config = $config;

	{
$this->cache = $cache;
$this->config = $config;

 
		$this->file_downloader = $file_downloader;

		$this->user = $user;

if (defined('PHPBB_QA'))

		$this->user = $user;

if (defined('PHPBB_QA'))

Line 80Line 107
	 * @param string $host Host (e.g. version.phpbb.com)
* @param string $path Path to file (e.g. /phpbb)
* @param string $file File name (Default: versions.json)

	 * @param string $host Host (e.g. version.phpbb.com)
* @param string $path Path to file (e.g. /phpbb)
* @param string $file File name (Default: versions.json)

 
	 * @param bool $use_ssl Use SSL or not (Default: false)

	 * @return version_helper
*/

	 * @return version_helper
*/

	public function set_file_location($host, $path, $file = 'versions.json')

	public function set_file_location($host, $path, $file = 'versions.json', $use_ssl = false)

	{
$this->host = $host;
$this->path = $path;
$this->file = $file;

	{
$this->host = $host;
$this->path = $path;
$this->file = $file;

 
		$this->use_ssl = $use_ssl;


return $this;
}


return $this;
}

Line 172Line 201
		$self = $this;
$current_version = $this->current_version;


		$self = $this;
$current_version = $this->current_version;


		// Filter out any versions less than to the current version

		// Filter out any versions less than the current version

		$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});

		$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});

Line 186Line 215

return $value;
});


return $value;
});

 
	}

/**
* Gets the latest update for the current branch the user is on
* Will suggest versions from newer branches when EoL has been reached
* and/or version from newer branch is needed for having all known security
* issues fixed.
*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return array Version info or empty array if there are no updates
* @throws \RuntimeException
*/
public function get_update_on_branch($force_update = false, $force_cache = false)
{
$versions = $this->get_versions_matching_stability($force_update, $force_cache);

$self = $this;
$current_version = $this->current_version;

// Filter out any versions less than the current version
$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});

// Get the lowest version from the previous list.
$update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) {
if ($value === null && $self->compare($data['current'], $current_version, '>='))
{
if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<=')))
{
return ($self->compare($data['current'], $current_version, '>')) ? $data : array();
}
else
{
return null;
}
}

return $value;
});

return $update_info === null ? array() : $update_info;
}

/**
* Gets the latest extension update for the current phpBB branch the user is on
* Will suggest versions from newer branches when EoL has been reached
* and/or version from newer branch is needed for having all known security
* issues fixed.
*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return array Version info or empty array if there are no updates
* @throws \RuntimeException
*/
public function get_ext_update_on_branch($force_update = false, $force_cache = false)
{
$versions = $this->get_versions_matching_stability($force_update, $force_cache);

$self = $this;
$current_version = $this->current_version;

// Get current phpBB branch from version, e.g.: 3.2
preg_match('/^(\d+\.\d+).*$/', $this->config['version'], $matches);
$current_branch = $matches[1];

// Filter out any versions less than the current version
$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});

// Filter out any phpbb branches less than the current version
$branches = array_filter(array_keys($versions), function($branch) use ($self, $current_branch) {
return $self->compare($branch, $current_branch, '>=');
});
if (!empty($branches))
{
$versions = array_intersect_key($versions, array_flip($branches));
}
else
{
// If branches are empty, it means the current phpBB branch is newer than any branch the
// extension was validated against. Reverse sort the versions array so we get the newest
// validated release available.
krsort($versions);
}

// Get the first available version from the previous list.
$update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) {
if ($value === null && $self->compare($data['current'], $current_version, '>='))
{
if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<=')))
{
return $self->compare($data['current'], $current_version, '>') ? $data : array();
}
else
{
return null;
}
}

return $value;
});

return $update_info === null ? array() : $update_info;

	}

/**

	}

/**

Line 193Line 328
	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	* @return string

	* @return array

	* @throws \RuntimeException
*/
public function get_suggested_updates($force_update = false, $force_cache = false)

	* @throws \RuntimeException
*/
public function get_suggested_updates($force_update = false, $force_cache = false)

Line 214Line 349
	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	* @return string Version info

	* @return array Version info

	* @throws \RuntimeException
*/
public function get_versions_matching_stability($force_update = false, $force_cache = false)

	* @throws \RuntimeException
*/
public function get_versions_matching_stability($force_update = false, $force_cache = false)

Line 234Line 369
	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.

	* @return string Version info, includes stable and unstable data

	* @return array Version info, includes stable and unstable data

	* @throws \RuntimeException
*/
public function get_versions($force_update = false, $force_cache = false)
{

	* @throws \RuntimeException
*/
public function get_versions($force_update = false, $force_cache = false)
{

		$cache_file = '_versioncheck_' . $this->host . $this->path . $this->file;

		$cache_file = '_versioncheck_' . $this->host . $this->path . $this->file . $this->use_ssl;


$info = $this->cache->get($cache_file);



$info = $this->cache->get($cache_file);


Line 249Line 384
		}
else if ($info === false || $force_update)
{

		}
else if ($info === false || $force_update)
{

			$errstr = $errno = '';
$info = get_remote_file($this->host, $this->path, $this->file, $errstr, $errno);








			try {
$info = $this->file_downloader->get($this->host, $this->path, $this->file, $this->use_ssl ? 443 : 80);
}
catch (\phpbb\exception\runtime_exception $exception)
{
$prepare_parameters = array_merge(array($exception->getMessage()), $exception->get_parameters());
throw new \RuntimeException(call_user_func_array(array($this->user, 'lang'), $prepare_parameters));
}
$error_string = $this->file_downloader->get_error_string();





			if (!empty($errstr))

			if (!empty($error_string))

			{

			{

				throw new \RuntimeException($errstr);

				throw new \RuntimeException($error_string);

			}

$info = json_decode($info, true);

			}

$info = json_decode($info, true);

 

// Sanitize any data we retrieve from a server
if (!empty($info))
{
$json_sanitizer = function (&$value, $key) {
$type_cast_helper = new \phpbb\request\type_cast_helper();
$type_cast_helper->set_var($value, $value, gettype($value), true);
};
array_walk_recursive($info, $json_sanitizer);
}


if (empty($info['stable']) && empty($info['unstable']))
{


if (empty($info['stable']) && empty($info['unstable']))
{

Line 266Line 418
				throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
}


				throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
}


			// Replace & with &amp; on announcement links
foreach ($info as $stability => $branches)



















			$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];

$info = $this->validate_versions($info);

$this->cache->put($cache_file, $info, 86400); // 24 hours
}

return $info;
}

/**
* Validate versions info input
*
* @param array $versions_info Decoded json data array. Will be modified
* and cleaned by this method
*
* @return array Versions info array
*/
public function validate_versions($versions_info)

			{

			{

				foreach ($branches as $branch => $branch_data)




		$array_diff = array_diff_key($versions_info, array($this->version_schema));

// Remove excessive data
if (count($array_diff) > 0)

				{

				{

					$info[$stability][$branch]['announcement'] = str_replace('&', '&amp;', $branch_data['announcement']);






			$old_versions_info = $versions_info;
$versions_info = array(
'stable' => !empty($old_versions_info['stable']) ? $old_versions_info['stable'] : array(),
'unstable' => !empty($old_versions_info['unstable']) ? $old_versions_info['unstable'] : array(),
);
unset($old_versions_info);

				}

				}

 

foreach ($versions_info as $stability_type => &$versions_data)
{
foreach ($versions_data as $branch => &$version_data)
{
if (!preg_match('/^[0-9a-z\-\.]+$/i', $branch))
{
unset($versions_data[$branch]);
continue;

			}


			}


			$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];

				$stability_diff = array_diff_key($version_data, $this->version_schema[$stability_type]);






			$this->cache->put($cache_file, $info, 86400); // 24 hours












				if (count($stability_diff) > 0)
{
$old_version_data = $version_data;
$version_data = array();
foreach ($this->version_schema[$stability_type] as $key => $value)
{
if (isset($old_version_data[$key]))
{
$version_data[$key] = $old_version_data[$key];
}
}
unset($old_version_data);

		}


		}


		return $info;






































				foreach ($version_data as $key => &$value)
{
if (!isset($this->version_schema[$stability_type][$key]))
{
unset($version_data[$key]);
throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_ENTRY'));
}

switch ($this->version_schema[$stability_type][$key])
{
case 'bool':
$value = (bool) $value;
break;

case 'url':
if (!empty($value) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $value) &&
!preg_match('#^' . get_preg_expression('www_url') . '$#iu', $value))
{
throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_URL'));
}
break;

case 'version':
if (!empty($value) && !preg_match(get_preg_expression('semantic_version'), $value))
{
throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_VERSION'));
}
break;

default:
// Shouldn't be possible to trigger this
throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_ENTRY'));
}
}
}
}

return $versions_info;

	}
}


	}
}