aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb/version_helper.php
diff options
context:
space:
mode:
authorNathan Guse <nathaniel.guse@gmail.com>2014-02-19 16:11:40 -0600
committerNathan Guse <nathaniel.guse@gmail.com>2014-02-19 16:13:23 -0600
commit6c8589775b8df2b6fbeffbe594d9279ae90e85ba (patch)
tree170b26bd86dce0eeb7d6c447115f6810ced34bc2 /phpBB/phpbb/version_helper.php
parentbd8951cfbec799f685eb89f14a83933cee647112 (diff)
downloadforums-6c8589775b8df2b6fbeffbe594d9279ae90e85ba.tar
forums-6c8589775b8df2b6fbeffbe594d9279ae90e85ba.tar.gz
forums-6c8589775b8df2b6fbeffbe594d9279ae90e85ba.tar.bz2
forums-6c8589775b8df2b6fbeffbe594d9279ae90e85ba.tar.xz
forums-6c8589775b8df2b6fbeffbe594d9279ae90e85ba.zip
[ticket/9871] Update version check file to use json format
PHPBB3-9871
Diffstat (limited to 'phpBB/phpbb/version_helper.php')
-rw-r--r--phpBB/phpbb/version_helper.php249
1 files changed, 249 insertions, 0 deletions
diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php
new file mode 100644
index 0000000000..df577c5dff
--- /dev/null
+++ b/phpBB/phpbb/version_helper.php
@@ -0,0 +1,249 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2014 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+namespace phpbb;
+
+/**
+ * Class to handle version checking and comparison
+ */
+class version_helper
+{
+ protected $cache;
+ protected $config;
+ protected $user;
+
+ public function __construct($cache, $config, $user)
+ {
+ $this->cache = $cache;
+ $this->config = $config;
+ $this->user = $user;
+ }
+
+ /**
+ * Wrapper for version_compare() that allows using uppercase A and B
+ * for alpha and beta releases.
+ *
+ * See http://www.php.net/manual/en/function.version-compare.php
+ *
+ * @param string $version1 First version number
+ * @param string $version2 Second version number
+ * @param string $operator Comparison operator (optional)
+ *
+ * @return mixed Boolean (true, false) if comparison operator is specified.
+ * Integer (-1, 0, 1) otherwise.
+ */
+ public function compare($version1, $version2, $operator = null)
+ {
+ $version1 = strtolower($version1);
+ $version2 = strtolower($version2);
+
+ if (is_null($operator))
+ {
+ return version_compare($version1, $version2);
+ }
+ else
+ {
+ return version_compare($version1, $version2, $operator);
+ }
+ }
+
+ /**
+ * Check whether or not a version is "stable"
+ *
+ * Stable means only numbers OR a pl release
+ *
+ * @param string $version
+ * @return bool Bool true or false
+ */
+ public function is_stable($version)
+ {
+ $matches = false;
+ preg_match('/^[\d\.]+/', $version, $matches);
+
+ if (empty($matches[0]))
+ {
+ return false;
+ }
+
+ return $this->compare($version, $matches[0], '>=');
+ }
+
+ /**
+ * Gets the latest version for the current branch the user is on
+ *
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @return string
+ * @throws \RuntimeException
+ */
+ public function get_latest_on_current_branch($force_update = false)
+ {
+ $versions = $this->get_versions_matching_stability($force_update);
+
+ $self = $this;
+ $current_version = $this->config['version'];
+
+ // Filter out any versions less than to 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.
+ return array_reduce($versions, function($value, $data) use ($self) {
+ if ($value === null || $self->compare($data['current'], $value, '<'))
+ {
+ return $data['current'];
+ }
+
+ return $value;
+ });
+ }
+
+ /**
+ * Obtains the latest version information
+ *
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @return string
+ * @throws \RuntimeException
+ */
+ public function get_suggested_updates($force_update = false)
+ {
+ $versions = $this->get_versions_matching_stability($force_update);
+
+ $self = $this;
+ $current_version = $this->config['version'];
+
+ // Filter out any versions less than or equal to the current version
+ return array_filter($versions, function($data) use ($self, $current_version) {
+ return $self->compare($data['current'], $current_version, '>');
+ });
+ }
+
+ /**
+ * Obtains the latest version information matching the stability of the current install
+ *
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @return string Version info
+ * @throws \RuntimeException
+ */
+ public function get_versions_matching_stability($force_update = false)
+ {
+ $info = $this->get_versions($force_update);
+
+ return ($this->is_stable($this->config['version']) && !defined('PHPBB_QA')) ? $info['stable'] : $info['unstable'];
+ }
+
+ /**
+ * Obtains the latest version information
+ *
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @return string Version info, includes stable and unstable data
+ * @throws \RuntimeException
+ */
+ public function get_versions($force_update = false)
+ {
+ $info = $this->cache->get('versioncheck');
+
+ if ($info === false || $force_update)
+ {
+ $info = $this->get_remote_file('version.phpbb.com', '/phpbb', 'versions.json');
+
+ $info = json_decode($info, true);
+
+ if (empty($info['stable']) || empty($info['unstable']))
+ {
+ $this->user->add_lang('acp/common');
+
+ throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
+ }
+
+ // Replace & with &amp; on announcement links
+ foreach ($info as $stability => $branches)
+ {
+ foreach ($branches as $branch => $branch_data)
+ {
+ $info[$stability][$branch]['announcement'] = str_replace('&', '&amp;', $branch_data['announcement']);
+ }
+ }
+
+ $this->cache->put('versioncheck', $info, 86400); // 24 hours
+ }
+
+ return $info;
+ }
+
+ /**
+ * Get remote file
+ *
+ * @param string $host Host, e.g. version.phpbb.com
+ * @param string $directory Directory, e.g. /phpbb
+ * @param string $filename Filename, e.g. versions.json
+ * @param int $port Port
+ * @param int $timeout Timeout (seconds)
+ * @return string Remote file contents
+ * @throws \RuntimeException
+ */
+ public function get_remote_file($host, $directory, $filename, $port = 80, $timeout = 6)
+ {
+ $errstr = $errno = false;
+
+ if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
+ {
+ @fputs($fsock, "GET $directory/$filename HTTP/1.0\r\n");
+ @fputs($fsock, "HOST: $host\r\n");
+ @fputs($fsock, "Connection: close\r\n\r\n");
+
+ $timer_stop = time() + $timeout;
+ stream_set_timeout($fsock, $timeout);
+
+ $file_info = '';
+ $get_info = false;
+
+ while (!@feof($fsock))
+ {
+ if ($get_info)
+ {
+ $file_info .= @fread($fsock, 1024);
+ }
+ else
+ {
+ $line = @fgets($fsock, 1024);
+ if ($line == "\r\n")
+ {
+ $get_info = true;
+ }
+ else if (stripos($line, '404 not found') !== false)
+ {
+ throw new \RuntimeException($this->user->lang('FILE_NOT_FOUND') . ': ' . $filename);
+ }
+ }
+
+ $stream_meta_data = stream_get_meta_data($fsock);
+
+ if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop)
+ {
+ throw new \RuntimeException($this->user->lang('FSOCK_TIMEOUT'));
+ }
+ }
+ @fclose($fsock);
+ }
+ else
+ {
+ if ($errstr)
+ {
+ throw new \RuntimeException(utf8_convert_message($errstr));
+ }
+ else
+ {
+ throw new \RuntimeException($this->user->lang('FSOCK_DISABLED'));
+ }
+ }
+
+ return $file_info;
+ }
+}