[ Index ]

PHP Cross Reference of phpBB-3.3.11-deutsch

title

Body

[close]

/phpbb/ -> version_helper.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb;
  15  
  16  use phpbb\exception\version_check_exception;
  17  
  18  /**
  19   * Class to handle version checking and comparison
  20   */
  21  class version_helper
  22  {
  23      /**
  24       * @var string Host
  25       */
  26      protected $host = 'version.phpbb.com';
  27  
  28      /**
  29       * @var string Path to file
  30       */
  31      protected $path = '/phpbb';
  32  
  33      /**
  34       * @var string File name
  35       */
  36      protected $file = 'versions.json';
  37  
  38      /**
  39       * @var bool Use SSL or not
  40       */
  41      protected $use_ssl = false;
  42  
  43      /**
  44       * @var string Current version installed
  45       */
  46      protected $current_version;
  47  
  48      /**
  49       * @var null|string Null to not force stability, 'unstable' or 'stable' to
  50       *                    force the corresponding stability
  51       */
  52      protected $force_stability;
  53  
  54      /** @var \phpbb\cache\service */
  55      protected $cache;
  56  
  57      /** @var \phpbb\config\config */
  58      protected $config;
  59  
  60      /** @var \phpbb\file_downloader */
  61      protected $file_downloader;
  62  
  63      protected $version_schema = array(
  64          'stable' => array(
  65              'current'        => 'version',
  66              'download'        => 'url',
  67              'announcement'    => 'url',
  68              'eol'            => 'url',
  69              'security'        => 'bool',
  70          ),
  71          'unstable' => array(
  72              'current'        => 'version',
  73              'download'        => 'url',
  74              'announcement'    => 'url',
  75              'eol'            => 'url',
  76              'security'        => 'bool',
  77          ),
  78      );
  79  
  80      /**
  81       * Constructor
  82       *
  83       * @param \phpbb\cache\service $cache
  84       * @param \phpbb\config\config $config
  85       * @param \phpbb\file_downloader $file_downloader
  86       */
  87  	public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader)
  88      {
  89          $this->cache = $cache;
  90          $this->config = $config;
  91          $this->file_downloader = $file_downloader;
  92  
  93          if (defined('PHPBB_QA'))
  94          {
  95              $this->force_stability = 'unstable';
  96          }
  97  
  98          $this->current_version = $this->config['version'];
  99      }
 100  
 101      /**
 102       * Set location to the file
 103       *
 104       * @param string $host Host (e.g. version.phpbb.com)
 105       * @param string $path Path to file (e.g. /phpbb)
 106       * @param string $file File name (Default: versions.json)
 107       * @param bool $use_ssl Use SSL or not (Default: false)
 108       * @return version_helper
 109       */
 110  	public function set_file_location($host, $path, $file = 'versions.json', $use_ssl = false)
 111      {
 112          $this->host = $host;
 113          $this->path = $path;
 114          $this->file = $file;
 115          $this->use_ssl = $use_ssl;
 116  
 117          return $this;
 118      }
 119  
 120      /**
 121       * Set current version
 122       *
 123       * @param string $version The current version
 124       * @return version_helper
 125       */
 126  	public function set_current_version($version)
 127      {
 128          $this->current_version = $version;
 129  
 130          return $this;
 131      }
 132  
 133      /**
 134       * Over-ride the stability to force check to include unstable versions
 135       *
 136       * @param null|string $stability Null to not force stability, 'unstable' or 'stable' to
 137       *                         force the corresponding stability
 138       * @return version_helper
 139       */
 140  	public function force_stability($stability)
 141      {
 142          $this->force_stability = $stability;
 143  
 144          return $this;
 145      }
 146  
 147      /**
 148       * Wrapper for version_compare() that allows using uppercase A and B
 149       * for alpha and beta releases.
 150       *
 151       * See http://www.php.net/manual/en/function.version-compare.php
 152       *
 153       * @param string $version1        First version number
 154       * @param string $version2        Second version number
 155       * @param string $operator        Comparison operator (optional)
 156       *
 157       * @return mixed                Boolean (true, false) if comparison operator is specified.
 158       *                                Integer (-1, 0, 1) otherwise.
 159       */
 160  	public function compare($version1, $version2, $operator = null)
 161      {
 162          return phpbb_version_compare($version1, $version2, $operator);
 163      }
 164  
 165      /**
 166       * Check whether or not a version is "stable"
 167       *
 168       * Stable means only numbers OR a pl release
 169       *
 170       * @param string $version
 171       * @return bool Bool true or false
 172       */
 173  	public function is_stable($version)
 174      {
 175          $matches = false;
 176          preg_match('/^[\d\.]+/', $version, $matches);
 177  
 178          if (empty($matches[0]))
 179          {
 180              return false;
 181          }
 182  
 183          return $this->compare($version, $matches[0], '>=');
 184      }
 185  
 186      /**
 187      * Gets the latest version for the current branch the user is on
 188      *
 189      * @param bool $force_update Ignores cached data. Defaults to false.
 190      * @param bool $force_cache Force the use of the cache. Override $force_update.
 191      * @return string
 192      * @throws version_check_exception
 193      */
 194  	public function get_latest_on_current_branch($force_update = false, $force_cache = false)
 195      {
 196          $versions = $this->get_versions_matching_stability($force_update, $force_cache);
 197  
 198          $self = $this;
 199          $current_version = $this->current_version;
 200  
 201          // Filter out any versions less than the current version
 202          $versions = array_filter($versions, function($data) use ($self, $current_version) {
 203              return $self->compare($data['current'], $current_version, '>=');
 204          });
 205  
 206          // Get the lowest version from the previous list.
 207          return array_reduce($versions, function($value, $data) use ($self) {
 208              if ($value === null || $self->compare($data['current'], $value, '<'))
 209              {
 210                  return $data['current'];
 211              }
 212  
 213              return $value;
 214          });
 215      }
 216  
 217      /**
 218       * Gets the latest update for the current branch the user is on
 219       * Will suggest versions from newer branches when EoL has been reached
 220       * and/or version from newer branch is needed for having all known security
 221       * issues fixed.
 222       *
 223       * @param bool $force_update Ignores cached data. Defaults to false.
 224       * @param bool $force_cache Force the use of the cache. Override $force_update.
 225       * @return array Version info or empty array if there are no updates
 226       * @throws \RuntimeException
 227       */
 228  	public function get_update_on_branch($force_update = false, $force_cache = false)
 229      {
 230          $versions = $this->get_versions_matching_stability($force_update, $force_cache);
 231  
 232          $self = $this;
 233          $current_version = $this->current_version;
 234  
 235          // Filter out any versions less than the current version
 236          $versions = array_filter($versions, function($data) use ($self, $current_version) {
 237              return $self->compare($data['current'], $current_version, '>=');
 238          });
 239  
 240          // Get the lowest version from the previous list.
 241          $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) {
 242              if ($value === null && $self->compare($data['current'], $current_version, '>='))
 243              {
 244                  if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<=')))
 245                  {
 246                      return ($self->compare($data['current'], $current_version, '>')) ? $data : array();
 247                  }
 248                  else
 249                  {
 250                      return null;
 251                  }
 252              }
 253  
 254              return $value;
 255          });
 256  
 257          return $update_info === null ? array() : $update_info;
 258      }
 259  
 260      /**
 261       * Gets the latest extension update for the current phpBB branch the user is on
 262       * Will suggest versions from newer branches when EoL has been reached
 263       * and/or version from newer branch is needed for having all known security
 264       * issues fixed.
 265       *
 266       * @param bool $force_update Ignores cached data. Defaults to false.
 267       * @param bool $force_cache Force the use of the cache. Override $force_update.
 268       * @return array Version info or empty array if there are no updates
 269       * @throws \RuntimeException
 270       */
 271  	public function get_ext_update_on_branch($force_update = false, $force_cache = false)
 272      {
 273          $versions = $this->get_versions_matching_stability($force_update, $force_cache);
 274  
 275          $self = $this;
 276          $current_version = $this->current_version;
 277  
 278          // Get current phpBB branch from version, e.g.: 3.2
 279          preg_match('/^(\d+\.\d+).*$/', $this->config['version'], $matches);
 280          $current_branch = $matches[1];
 281  
 282          // Filter out any versions less than the current version
 283          $versions = array_filter($versions, function($data) use ($self, $current_version) {
 284              return $self->compare($data['current'], $current_version, '>=');
 285          });
 286  
 287          // Filter out any phpbb branches less than the current version
 288          $branches = array_filter(array_keys($versions), function($branch) use ($self, $current_branch) {
 289              return $self->compare($branch, $current_branch, '>=');
 290          });
 291          if (!empty($branches))
 292          {
 293              $versions = array_intersect_key($versions, array_flip($branches));
 294          }
 295          else
 296          {
 297              // If branches are empty, it means the current phpBB branch is newer than any branch the
 298              // extension was validated against. Reverse sort the versions array so we get the newest
 299              // validated release available.
 300              krsort($versions);
 301          }
 302  
 303          // Get the first available version from the previous list.
 304          $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) {
 305              if ($value === null && $self->compare($data['current'], $current_version, '>='))
 306              {
 307                  if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<=')))
 308                  {
 309                      return $self->compare($data['current'], $current_version, '>') ? $data : array();
 310                  }
 311                  else
 312                  {
 313                      return null;
 314                  }
 315              }
 316  
 317              return $value;
 318          });
 319  
 320          return $update_info === null ? array() : $update_info;
 321      }
 322  
 323      /**
 324      * Obtains the latest version information
 325      *
 326      * @param bool $force_update Ignores cached data. Defaults to false.
 327      * @param bool $force_cache Force the use of the cache. Override $force_update.
 328      * @return array
 329      * @throws version_check_exception
 330      */
 331  	public function get_suggested_updates($force_update = false, $force_cache = false)
 332      {
 333          $versions = $this->get_versions_matching_stability($force_update, $force_cache);
 334  
 335          $self = $this;
 336          $current_version = $this->current_version;
 337  
 338          // Filter out any versions less than or equal to the current version
 339          return array_filter($versions, function($data) use ($self, $current_version) {
 340              return $self->compare($data['current'], $current_version, '>');
 341          });
 342      }
 343  
 344      /**
 345      * Obtains the latest version information matching the stability of the current install
 346      *
 347      * @param bool $force_update Ignores cached data. Defaults to false.
 348      * @param bool $force_cache Force the use of the cache. Override $force_update.
 349      * @return array Version info
 350      * @throws version_check_exception
 351      */
 352  	public function get_versions_matching_stability($force_update = false, $force_cache = false)
 353      {
 354          $info = $this->get_versions($force_update, $force_cache);
 355  
 356          if ($this->force_stability !== null)
 357          {
 358              return ($this->force_stability === 'unstable') ? $info['unstable'] : $info['stable'];
 359          }
 360  
 361          return ($this->is_stable($this->current_version)) ? $info['stable'] : $info['unstable'];
 362      }
 363  
 364      /**
 365      * Obtains the latest version information
 366      *
 367      * @param bool $force_update Ignores cached data. Defaults to false.
 368      * @param bool $force_cache Force the use of the cache. Override $force_update.
 369      * @return array Version info, includes stable and unstable data
 370      * @throws version_check_exception
 371      */
 372  	public function get_versions($force_update = false, $force_cache = false)
 373      {
 374          $cache_file = '_versioncheck_' . $this->host . $this->path . $this->file . $this->use_ssl;
 375  
 376          $info = $this->cache->get($cache_file);
 377  
 378          if ($info === false && $force_cache)
 379          {
 380              throw new version_check_exception('VERSIONCHECK_FAIL');
 381          }
 382          else if ($info === false || $force_update)
 383          {
 384              $info = $this->file_downloader->get($this->host, $this->path, $this->file, $this->use_ssl ? 443 : 80);
 385              $error_string = $this->file_downloader->get_error_string();
 386  
 387              if (!empty($error_string))
 388              {
 389                  throw new version_check_exception($error_string);
 390              }
 391  
 392              $info = json_decode($info, true);
 393  
 394              // Sanitize any data we retrieve from a server
 395              if (!empty($info))
 396              {
 397                  $json_sanitizer = function (&$value, $key) {
 398                      $type_cast_helper = new \phpbb\request\type_cast_helper();
 399                      $type_cast_helper->set_var($value, $value, gettype($value), true);
 400                  };
 401                  array_walk_recursive($info, $json_sanitizer);
 402              }
 403  
 404              if (empty($info['stable']) && empty($info['unstable']))
 405              {
 406                  throw new version_check_exception('VERSIONCHECK_FAIL');
 407              }
 408  
 409              $info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
 410              $info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];
 411  
 412              $info = $this->validate_versions($info);
 413  
 414              $this->cache->put($cache_file, $info, 86400); // 24 hours
 415          }
 416  
 417          return $info;
 418      }
 419  
 420      /**
 421       * Validate versions info input
 422       *
 423       * @param array $versions_info Decoded json data array. Will be modified
 424       *        and cleaned by this method
 425       *
 426       * @return array Versions info array
 427       * @throws version_check_exception
 428       */
 429  	public function validate_versions($versions_info)
 430      {
 431          $array_diff = array_diff_key($versions_info, array($this->version_schema));
 432  
 433          // Remove excessive data
 434          if (count($array_diff) > 0)
 435          {
 436              $old_versions_info = $versions_info;
 437              $versions_info = array(
 438                  'stable'    => !empty($old_versions_info['stable']) ? $old_versions_info['stable'] : array(),
 439                  'unstable'    => !empty($old_versions_info['unstable']) ? $old_versions_info['unstable'] : array(),
 440              );
 441              unset($old_versions_info);
 442          }
 443  
 444          foreach ($versions_info as $stability_type => &$versions_data)
 445          {
 446              foreach ($versions_data as $branch => &$version_data)
 447              {
 448                  if (!preg_match('/^[0-9a-z\-\.]+$/i', $branch))
 449                  {
 450                      unset($versions_data[$branch]);
 451                      continue;
 452                  }
 453  
 454                  $stability_diff = array_diff_key($version_data, $this->version_schema[$stability_type]);
 455  
 456                  if (count($stability_diff) > 0)
 457                  {
 458                      $old_version_data = $version_data;
 459                      $version_data = array();
 460                      foreach ($this->version_schema[$stability_type] as $key => $value)
 461                      {
 462                          if (isset($old_version_data[$key]))
 463                          {
 464                              $version_data[$key] = $old_version_data[$key];
 465                          }
 466                      }
 467                      unset($old_version_data);
 468                  }
 469  
 470                  foreach ($version_data as $key => &$value)
 471                  {
 472                      if (!isset($this->version_schema[$stability_type][$key]))
 473                      {
 474                          unset($version_data[$key]);
 475                          throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY');
 476                      }
 477  
 478                      switch ($this->version_schema[$stability_type][$key])
 479                      {
 480                          case 'bool':
 481                              $value = (bool) $value;
 482                          break;
 483  
 484                          case 'url':
 485                              if (!empty($value) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $value) &&
 486                                  !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $value))
 487                              {
 488                                  throw new version_check_exception('VERSIONCHECK_INVALID_URL');
 489                              }
 490                          break;
 491  
 492                          case 'version':
 493                              if (!empty($value) && !preg_match(get_preg_expression('semantic_version'), $value))
 494                              {
 495                                  throw new version_check_exception('VERSIONCHECK_INVALID_VERSION');
 496                              }
 497                          break;
 498  
 499                          default:
 500                              // Shouldn't be possible to trigger this
 501                              throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY');
 502                      }
 503                  }
 504              }
 505          }
 506  
 507          return $versions_info;
 508      }
 509  }


Generated: Sat Nov 4 14:26:03 2023 Cross-referenced by PHPXref 0.7.1