Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

version_helper.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 14.21 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb;
015   
016  use phpbb\exception\version_check_exception;
017   
018  /**
019   * Class to handle version checking and comparison
020   */
021  class version_helper
022  {
023      /**
024       * @var string Host
025       */
026      protected $host = 'version.phpbb.com';
027   
028      /**
029       * @var string Path to file
030       */
031      protected $path = '/phpbb';
032   
033      /**
034       * @var string File name
035       */
036      protected $file = 'versions.json';
037   
038      /**
039       * @var bool Use SSL or not
040       */
041      protected $use_ssl = false;
042   
043      /**
044       * @var string Current version installed
045       */
046      protected $current_version;
047   
048      /**
049       * @var null|string Null to not force stability, 'unstable' or 'stable' to
050       *                    force the corresponding stability
051       */
052      protected $force_stability;
053   
054      /** @var \phpbb\cache\service */
055      protected $cache;
056   
057      /** @var \phpbb\config\config */
058      protected $config;
059   
060      /** @var \phpbb\file_downloader */
061      protected $file_downloader;
062   
063      protected $version_schema = array(
064          'stable' => array(
065              'current'        => 'version',
066              'download'        => 'url',
067              'announcement'    => 'url',
068              'eol'            => 'url',
069              'security'        => 'bool',
070          ),
071          'unstable' => array(
072              'current'        => 'version',
073              'download'        => 'url',
074              'announcement'    => 'url',
075              'eol'            => 'url',
076              'security'        => 'bool',
077          ),
078      );
079   
080      /**
081       * Constructor
082       *
083       * @param \phpbb\cache\service $cache
084       * @param \phpbb\config\config $config
085       * @param \phpbb\file_downloader $file_downloader
086       */
087      public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader)
088      {
089          $this->cache = $cache;
090          $this->config = $config;
091          $this->file_downloader = $file_downloader;
092   
093          if (defined('PHPBB_QA'))
094          {
095              $this->force_stability = 'unstable';
096          }
097   
098          $this->current_version = $this->config['version'];
099      }
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, 30);
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  }
510