Phorum PHP Cross Reference Discussion Forums

Source: /include/version_functions.php - 409 lines - 17034 bytes - Summary - Text - Print

   1  <?php
   2  ////////////////////////////////////////////////////////////////////////////////
   3  //                                                                            //
   4  //   Copyright (C) 2010  Phorum Development Team                              //
   5  //   http://www.phorum.org                                                    //
   6  //                                                                            //
   7  //   This program is free software. You can redistribute it and/or modify     //
   8  //   it under the terms of either the current Phorum License (viewable at     //
   9  //   phorum.org) or the Phorum License that was distributed with this file    //
  10  //                                                                            //
  11  //   This program is distributed in the hope that it will be useful,          //
  12  //   but WITHOUT ANY WARRANTY, without even the implied warranty of           //
  13  //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     //
  14  //                                                                            //
  15  //   You should have received a copy of the Phorum License                    //
  16  //   along with this program.                                                 //
  17  //                                                                            //
  18  ////////////////////////////////////////////////////////////////////////////////
  19  
  20  if (!defined("PHORUM")) return;
  21  
  22  // The internal_patchlevel can be unset, because this setting was
  23  // added in 5.2. When upgrading from 5.1, this settings is not yet
  24  // available. To make things work, we'll fake a value for this
  25  // setting which will always be lower than the available patch ids.
  26  if (!isset($PHORUM["internal_patchlevel"])) {
  27      $PHORUM["internal_patchlevel"] = "1111111111";
  28  }
  29  
  30  /**
  31   * Parses a Phorum version number.
  32   *
  33   * The following version numberings are recognized:
  34   *
  35   * - Snapshot release, e.g. "phorum5-svn-2007121315".
  36   *   We only have one version element for these.
  37   *   The returned release type will be "snapshot".
  38   *
  39   * - Development release from the downloads section at phorum.org,
  40   *   e.g. "5.1.10-alpha", "5.2.1-beta" or "5.2.2-RC1". The returned
  41   *   release type will be "development" and the version will contain
  42   *   three elements.
  43   *
  44   * - Stable release, e.g. "5.1.20" or "5.1.16a". A letter can be appended
  45   *   to indicate a quick fix release. We let the letter come back as a
  46   *   numerical value in the fourth element of the returned version array,
  47   *   (where a = 1, b = 2, etc) or 0 (zero) if no quick fix version is
  48   *   available. Normally, we shouldn't get further than an "a" or "b"
  49   *   quick fix release. The returned release type will be "stable".
  50   *
  51   * - Development release from the subversion repository, e.g. "5.2-dev".
  52   *   The version will have two elements. The returned release type
  53   *   will be "repository".
  54   *
  55   * If the version number cannot be parsed, then the returned release
  56   * type will be "unknown" and the parsed version will be an empty array.
  57   * This case should never happen of course.
  58   *
  59   * @param string $version
  60   *     The version number to parse.
  61   *
  62   * @return array
  63   *     An array containing three elements:
  64   *     - The release type, which can be "unknown" (parse failed),
  65   *       "alpha", "beta", "development" (if something else than the
  66   *       previous two were used for a development version), "snapshot",
  67   *       "repository", "candidate" or "stable".
  68   *     - An array containing the parsed version. This version is an
  69   *       array containing a split up version number, with zero to five
  70   *       elements in it (only relevant version parts are added).
  71   *     - The version number that was parsed.
  72   */
  73  function phorum_parse_version($version)
  74  {
  75      // Snapshot release, e.g. "phorum5-svn-2007121315".
  76      if (preg_match('/^phorum(\d+)-svn-\d+$/', $version, $m)) {
  77          $release = 'snapshot';
  78          $parsed_version = array($m[1]);
  79      // Stable release, e.g. "5.1.20" or "5.1.16a".
  80      } elseif (preg_match('/^(\d+)\.(\d+).(\d+)([a-z])?$/', $version, $m)) {
  81          $release = 'stable';
  82          $subrelease = empty($m[4]) ? 0 : ord($m[4])-96; // ord('a') = 97;
  83          $parsed_version = array($m[1], $m[2], $m[3], $subrelease);
  84      // Release candidate, e.g. "5.1.26-RC1" or "5.2.10a-RC2".
  85      } elseif (preg_match('/^(\d+)\.(\d+).(\d+)([a-z])?-RC(\d+)$/', $version, $m)) {
  86          $release = 'candidate';
  87          $subrelease = empty($m[4]) ? 0 : ord($m[4])-96; // ord('a') = 97;
  88          $parsed_version = array($m[1], $m[2], $m[3], $subrelease, $m[5]);
  89      // Development release from a subversion tree, e.g. "5.2-dev".
  90      } elseif (preg_match('/^(\d+)\.(\d+)(-\w+)?$/', $version, $m)) {
  91          $release = 'repository';
  92          $parsed_version = array($m[1], $m[2]);
  93      // Development release, e.g. "5.1.10-alpha", "5.2.1a-beta".
  94      } elseif (preg_match('/^(\d+)\.(\d+).(\d+)([a-z])?-(\w+)$/', $version, $m)) {
  95          if ($m[5] == 'alpha')    $release = 'alpha';
  96          elseif ($m[5] == 'beta') $release = 'beta';
  97          else                     $release = 'development';
  98          $subrelease = empty($m[4]) ? 0 : ord($m[4])-96; // ord('a') = 97;
  99          $parsed_version = array($m[1], $m[2], $m[3], $subrelease);
 100      // We should never get here.
 101      } else {
 102          $release = 'unknown';
 103          $parsed_version = array();
 104      }
 105  
 106      return array($release, $parsed_version, $version);
 107  }
 108  
 109  /**
 110   * Compares two version numbers.
 111   *
 112   * This function will tell which of two version numbers is higher.
 113   *
 114   * @param array version1
 115   *     The first version number. Either the version number or the
 116   *     return array from phorum_parse_version().
 117   *
 118   * @param array version2
 119   *     The second version number. Either the version number or the
 120   *     return array from phorum_parse_version().
 121   *
 122   * @return integer
 123   *      1 if version1 is higher than version2.
 124   *      0 if they are equal.
 125   *     -1 if version1 is lower lower than version2.
 126   */
 127  function phorum_compare_version($version1, $version2)
 128  {
 129      // Parse version numbers if no parsed arrays were provided.
 130      if (!is_array($version1)) $version1 = phorum_parse_version($version1);
 131      if (!is_array($version2)) $version2 = phorum_parse_version($version2);
 132  
 133      // Compare relevant parts of the parsed version numbers to see
 134      // what version is higher.
 135      for ($s=0; $s<=4; $s++) {
 136          if (!isset($version1[1][$s]) || !isset($version2[1][$s])) break;
 137          if ($version1[1][$s] > $version2[1][$s]) return +1;
 138          if ($version1[1][$s] < $version2[1][$s]) return -1;
 139      }
 140  
 141      // No difference was found. In this case, we consider the release type.
 142      // Repository can of course be a lower release than a stable one,
 143      // but we always see it as a higher release. People that use development
 144      // releases should know what they are doing.
 145      $order = array(
 146          'unknown'     => 0,
 147          'alpha'       => 1,
 148          'beta'        => 2,
 149          'development' => 3,
 150          'candidate'   => 4,
 151          'stable'      => 5,
 152          'snapshot'    => 6,
 153          'repository'  => 7
 154      );
 155  
 156      $t1 = $order[$version1[0]];
 157      $t2 = $order[$version2[0]];
 158  
 159      if ($t1 == $t2)    return 0;
 160      elseif ($t1 < $t2) return -1;
 161      else               return +1;
 162  }
 163  
 164  /**
 165   * Retrieves the available software versions from the Phorum website.
 166   * The format of the data returned from the server is two lines. The first
 167   * line is for the stable version and the second for the development version.
 168   * Each line contains pipe separated values, with the following fields in it:
 169   * <version>|<release date>|<downloadloc 1>|<downloadloc 2>|...|<downloadloc n>
 170   *
 171   * @return releases - An array of releases for release types
 172   *                    "stable" and "development".
 173   */
 174  function phorum_available_releases()
 175  {
 176      $releases = array();
 177      $fp = @fopen("http://phorum.org/version.php", "r");
 178      if ($fp) {
 179          foreach (array("stable", "development") as $release) {
 180              $line = fgets($fp, 1024);
 181              if (strstr($line, '|')) {
 182                  $fields = explode('|', $line);
 183                  if (count($fields) >= 3) {
 184                      // See if we can parse the version and if the parsed
 185                      // release type matches the release type we're expecting.
 186                      $parsed_version = phorum_parse_version($fields[0]);
 187                      if ($parsed_version[0] == $release) {
 188                          $releases[$release] = array(
 189                              "version"   => array_shift($fields),
 190                              "pversion"  => $parsed_version,
 191                              "date"      => array_shift($fields),
 192                              "locations" => $fields
 193                          );
 194                      }
 195                  }
 196              }
 197          }
 198          fclose($fp);
 199      }
 200  
 201      return $releases;
 202  }
 203  
 204  /**
 205   * Finds out if there are any upgrades available for a version of Phorum.
 206   *
 207   * @param version - the version to check for (default is the running version)
 208   * @return releases - An array of available releases with the
 209   *         "upgrade" field set in case the release would be an
 210   *         upgrade for the currently running Phorum software.
 211   */
 212  function phorum_find_upgrades($version = PHORUM)
 213  {
 214      // Parse the running version of phorum.
 215      $running_version = phorum_parse_version($version);
 216  
 217      // Retrieve the available releases.
 218      $releases = phorum_available_releases();
 219  
 220      // Check if an upgrade is available for the running release.
 221      // If we're running a stable version, we only compare to the current
 222      // stable release. If we're running a development version, we compare both
 223      // stable and development.
 224      if (isset($releases["stable"])) {
 225          $avail_version = $releases["stable"]["pversion"];
 226          if (phorum_compare_version($running_version, $avail_version) == -1) {
 227              $releases["stable"]["upgrade"] = true;
 228          } else {
 229              $releases["stable"]["upgrade"] = false;
 230          }
 231      }
 232      if (($running_version[0] == 'development' ||
 233           $running_version[0] == 'snapshot') &&
 234           isset($releases["development"])) {
 235          $avail_version = $releases["development"]["pversion"];
 236          if (phorum_compare_version($running_version, $avail_version) == -1) {
 237              $releases["development"]["upgrade"] = true;
 238          } else {
 239              $releases["development"]["upgrade"] = false;
 240          }
 241      }
 242  
 243      return $releases;
 244  }
 245  
 246  /**
 247   * Retrieves all database patches and upgrades that have not yet
 248   * been processed.
 249   *
 250   * @return array $upgradefiles
 251   *     An array of upgradefiles. The keys in the array are "<version>-<type>",
 252   *     where <type> is either "patch" or "schema". The values are arrays with
 253   *     the following fields set:
 254   *       - version: the version of the upgrade file
 255   *       - type: the type of upgrade ("patch" or "schema")
 256   *       - file: the path to the upgrade file
 257   *     The array is sorted by version number.
 258   */
 259  function phorum_dbupgrade_getupgrades()
 260  {
 261      global $PHORUM;
 262  
 263      // Find the core type for the used db layer. By default, the core type
 264      // is the same as the db layer type. A db layer can however override the
 265      // core type to hike along with database upgrades from another database
 266      // layer. This allows for example to have the mysqli and mysql layers
 267      // share the same core type (since their only real difference is not in
 268      // the database schema/data, but in the use of different PHP calls).
 269      $core_type = isset($PHORUM['DBCONFIG']['core_type'])
 270                 ? $PHORUM['DBCONFIG']['core_type']
 271                 : $PHORUM['DBCONFIG']['type'];
 272      $core_type = basename($core_type);
 273  
 274      // Go over both the patches and schema upgrades and find all
 275      // upgrades that have not yet been processed.
 276      $upgrades = array();
 277      foreach (array('patch', 'schema') as $type)
 278      {
 279          $upgradepath =
 280              "./include/db/upgrade/$core_type" .
 281              ($type == 'patch' ? '-patches' : '');
 282  
 283          $curversion = $type == 'patch'
 284                      ? $PHORUM['internal_patchlevel']
 285                      : $PHORUM['internal_version'];
 286  
 287          $wantversion = $type == 'patch'
 288                      ? PHORUM_SCHEMA_PATCHLEVEL
 289                      : PHORUM_SCHEMA_VERSION;
 290  
 291          // Find all available upgrade files in the upgrade directory.
 292          // Upgrade file are in the format YYYYMMDDSS.php, where
 293          // Y = year, M = month, D = day, S = serial.
 294          // Example: "2007031700.php".
 295          if (($dh =@opendir($upgradepath)) === FALSE) die (
 296              "phorum_dbupgrade_getupgrades(): unable to open the upgrade " .
 297              "directory " . htmlspecialchars($upgradepath)
 298          );
 299          while (($file = readdir ($dh)) !== FALSE) {
 300              if (preg_match('/^(\d{10})\.php$/', $file, $m)) {
 301                  $version = $m[1];
 302                  if ($version > $curversion && $version <= $wantversion) {
 303                      $upgrades["$version-$type"] = array(
 304                          "version" => $version,
 305                          "type"    => $type,
 306                          "file"    => "$upgradepath/$file"
 307                      );
 308                  }
 309              }
 310          }
 311          unset($file);
 312          closedir($dh);
 313      }
 314  
 315      // Sort the upgradefiles. We can use a standard sort here,
 316      // since they are in the strict YYYYMMDDSS-<type> format.
 317      // The version numbers will be leading for the sort. If the
 318      // same version is available as a patch and a schema upgrade,
 319      // then the patch will come before the schema upgrade.
 320      asort($upgrades);
 321  
 322      return $upgrades;
 323  }
 324  
 325  /**
 326   * Perform the upgrade for a single upgrade file.
 327   *
 328   * @param $upgrades - An upgrade description. One element from the array
 329   *                    as returned by phorum_dbupgrade_getupgrades().
 330   * @param $update_internal_version - whether to update the internal version
 331   *                    for Phorum or not. This one is TRUE by default.
 332   *                    It can be used by scripts that have to re-run an old
 333   *                    single upgrade file and for which the internal version
 334   *                    should not be put back to an old value.
 335   * @return $msg - Describes the results of the upgrade.
 336   */
 337  function phorum_dbupgrade_run($upgrade, $update_internal_version = TRUE)
 338  {
 339      $PHORUM      = $GLOBALS["PHORUM"];
 340      $version     = $upgrade["version"];
 341      $type        = $upgrade["type"];
 342      $upgradefile = $upgrade["file"];
 343  
 344      $versionvar = $type == 'patch' ? 'internal_patchlevel':'internal_version';
 345  
 346      // Find the version from which we're upgrading.
 347      $fromversion = $PHORUM[$versionvar];
 348  
 349      // Executing large, long running scripts can result in problems,
 350      // in case the script hits PHP resource boundaries. Here we try
 351      // to prepare the PHP environment for the upgrade. Unfortunately,
 352      // if the server is running with safe_mode enabled, we cannot
 353      // change the execution time and memory limits.
 354      if (! ini_get('safe_mode')) {
 355          set_time_limit(0);
 356          ini_set("memory_limit","64M");
 357      }
 358  
 359      // Check if the upgradefile is readable.
 360      if (file_exists($upgradefile) && is_readable($upgradefile))
 361      {
 362          // Initialize the return message.
 363          if (!$update_internal_version) {
 364              $msg = "Installing patch $version ...<br/>\n";
 365          }
 366          // Patch level 1111111111 is a special value that is used by
 367          // phorum if there is no patch level stored in the database.
 368          // So this is the first time a patch is installed.
 369          elseif ($fromversion == '1111111111') {
 370              $msg = "Upgrading to patch level $version ...<br/>\n";
 371          } else {
 372              $msg = "Upgrading from " .
 373                     ($type == "patch"?"patch level ":"database version ") .
 374                     "$fromversion to $version ...<br/>\n";
 375          }
 376  
 377          // Load the upgrade file. The upgrade file should fill the
 378          // $upgrade_queries array with the necessary queries to run.
 379          $upgrade_queries = array();
 380          include($upgradefile);
 381  
 382          // Run the upgrade queries.
 383          $err = phorum_db_run_queries($upgrade_queries);
 384          if($err !== NULL){
 385              $msg.= "An error occured during this upgrade:<br/><br/>\n" .
 386                     "<span style=\"color:red\">$err</span><br/><br/>\n" .
 387                     "Please make note of this error and contact the " .
 388                     "Phorum Dev Team for help.\nYou can try to continue " .
 389                     "with the rest of the upgrade.<br/>\n";
 390          } else {
 391              $msg.= "The upgrade was successful.<br/>\n";
 392          }
 393  
 394          // Update the upgrade version info.
 395          if ($update_internal_version) {
 396              $GLOBALS["PHORUM"][$versionvar] = $version;
 397              phorum_db_update_settings(array($versionvar => $version));
 398          }
 399  
 400          return $msg;
 401  
 402      } else {
 403          return "The upgrade file ".htmlspecialchars($upgradefile)." " .
 404                 "cannot be opened by Phorum for reading. Please check " .
 405                 "the file permissions for this file and try again.";
 406      }
 407  }
 408  
 409  ?>

title

Description

title

Description

title

Description

title

title

Body