1<?php 2namespace TYPO3\CMS\Core\Utility; 3 4/* 5 * This file is part of the TYPO3 CMS project. 6 * 7 * It is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License, either version 2 9 * of the License, or any later version. 10 * 11 * For the full copyright and license information, please read the 12 * LICENSE.txt file that was distributed with this source code. 13 * 14 * The TYPO3 project - inspiring people to share! 15 */ 16 17/** 18 * Class with helper functions for version number handling 19 */ 20class VersionNumberUtility 21{ 22 /** 23 * Returns an integer from a three part version number, eg '4.12.3' -> 4012003 24 * 25 * @param string $versionNumber Version number on format x.x.x 26 * @return int Integer version of version number (where each part can count to 999) 27 */ 28 public static function convertVersionNumberToInteger($versionNumber) 29 { 30 $versionParts = explode('.', $versionNumber); 31 $version = $versionParts[0]; 32 for ($i = 1; $i < 3; $i++) { 33 if (!empty($versionParts[$i])) { 34 $version .= str_pad((int)$versionParts[$i], 3, '0', STR_PAD_LEFT); 35 } else { 36 $version .= '000'; 37 } 38 } 39 return (int)$version; 40 } 41 42 /** 43 * Returns the three part version number (string) from an integer, eg 4012003 -> '4.12.3' 44 * 45 * @param int $versionInteger Integer representation of version number 46 * @return string Version number as format x.x.x 47 * @throws \InvalidArgumentException if $versionInteger is not an integer 48 */ 49 public static function convertIntegerToVersionNumber($versionInteger) 50 { 51 if (!is_int($versionInteger)) { 52 throw new \InvalidArgumentException(\TYPO3\CMS\Core\Utility\VersionNumberUtility::class . '::convertIntegerToVersionNumber() supports an integer argument only!', 1334072223); 53 } 54 $versionString = str_pad($versionInteger, 9, '0', STR_PAD_LEFT); 55 $parts = [ 56 substr($versionString, 0, 3), 57 substr($versionString, 3, 3), 58 substr($versionString, 6, 3) 59 ]; 60 return (int)$parts[0] . '.' . (int)$parts[1] . '.' . (int)$parts[2]; 61 } 62 63 /** 64 * Splits a version range into an array. 65 * 66 * If a single version number is given, it is considered a minimum value. 67 * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed. 68 * If no version can be parsed "0.0.0" — "0.0.0" is the result 69 * 70 * @param string $version A string with a version range. 71 * @return array 72 */ 73 public static function splitVersionRange($version) 74 { 75 $versionRange = []; 76 if (strstr($version, '-')) { 77 $versionRange = explode('-', $version, 2); 78 } else { 79 $versionRange[0] = $version; 80 $versionRange[1] = ''; 81 } 82 if (!$versionRange[0]) { 83 $versionRange[0] = '0.0.0'; 84 } 85 if (!$versionRange[1]) { 86 $versionRange[1] = '0.0.0'; 87 } 88 return $versionRange; 89 } 90 91 /** 92 * Removes -dev -alpha -beta -RC states (also without '-' prefix) from a version number 93 * and replaces them by .0 and normalizes to a three part version number 94 * 95 * @return string 96 */ 97 public static function getNumericTypo3Version() 98 { 99 $t3version = static::getCurrentTypo3Version(); 100 $t3version = preg_replace('/-?(dev|alpha|beta|RC).*$/', '', $t3version); 101 $parts = GeneralUtility::intExplode('.', $t3version . '..'); 102 $t3version = MathUtility::forceIntegerInRange($parts[0], 0, 999) . '.' . 103 MathUtility::forceIntegerInRange($parts[1], 0, 999) . '.' . 104 MathUtility::forceIntegerInRange($parts[2], 0, 999); 105 return $t3version; 106 } 107 108 /** 109 * Wrapper function for TYPO3_version constant to make functions using 110 * the constant unit testable 111 * 112 * @return string 113 */ 114 public static function getCurrentTypo3Version() 115 { 116 return TYPO3_version; 117 } 118 119 /** 120 * This function converts version range strings (like '4.2.0-4.4.99') to an array 121 * (like array('4.2.0', '4.4.99'). It also forces each version part to be between 122 * 0 and 999 123 * 124 * @param string $versionsString 125 * @return array 126 */ 127 public static function convertVersionsStringToVersionNumbers($versionsString) 128 { 129 $versions = GeneralUtility::trimExplode('-', $versionsString); 130 $versionsCount = count($versions); 131 for ($i = 0; $i < $versionsCount; $i++) { 132 $cleanedVersion = GeneralUtility::trimExplode('.', $versions[$i]); 133 $cleanedVersionCount = count($cleanedVersion); 134 for ($j = 0; $j < $cleanedVersionCount; $j++) { 135 $cleanedVersion[$j] = MathUtility::forceIntegerInRange($cleanedVersion[$j], 0, 999); 136 } 137 $cleanedVersionString = implode('.', $cleanedVersion); 138 if (static::convertVersionNumberToInteger($cleanedVersionString) === 0) { 139 $cleanedVersionString = ''; 140 } 141 $versions[$i] = $cleanedVersionString; 142 } 143 return $versions; 144 } 145 146 /** 147 * Parses the version number x.x.x and returns an array with the various parts. 148 * It also forces each … 0 to 999 149 * 150 * @param string $version Version code, x.x.x 151 * @return array 152 */ 153 public static function convertVersionStringToArray($version) 154 { 155 $parts = GeneralUtility::intExplode('.', $version . '..'); 156 $parts[0] = MathUtility::forceIntegerInRange($parts[0], 0, 999); 157 $parts[1] = MathUtility::forceIntegerInRange($parts[1], 0, 999); 158 $parts[2] = MathUtility::forceIntegerInRange($parts[2], 0, 999); 159 $result = []; 160 $result['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2]; 161 $result['version_int'] = (int)($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]); 162 $result['version_main'] = $parts[0]; 163 $result['version_sub'] = $parts[1]; 164 $result['version_dev'] = $parts[2]; 165 return $result; 166 } 167 168 /** 169 * Method to raise a version number 170 * 171 * @param string $raise one of "main", "sub", "dev" - the version part to raise by one 172 * @param string $version (like 4.1.20) 173 * @return string 174 * @throws \TYPO3\CMS\Core\Exception 175 */ 176 public static function raiseVersionNumber($raise, $version) 177 { 178 if (!in_array($raise, ['main', 'sub', 'dev'])) { 179 throw new \TYPO3\CMS\Core\Exception('RaiseVersionNumber expects one of "main", "sub" or "dev".', 1342639555); 180 } 181 $parts = GeneralUtility::intExplode('.', $version . '..'); 182 $parts[0] = MathUtility::forceIntegerInRange($parts[0], 0, 999); 183 $parts[1] = MathUtility::forceIntegerInRange($parts[1], 0, 999); 184 $parts[2] = MathUtility::forceIntegerInRange($parts[2], 0, 999); 185 switch ((string)$raise) { 186 case 'main': 187 $parts[0]++; 188 $parts[1] = 0; 189 $parts[2] = 0; 190 break; 191 case 'sub': 192 $parts[1]++; 193 $parts[2] = 0; 194 break; 195 case 'dev': 196 $parts[2]++; 197 break; 198 } 199 return $parts[0] . '.' . $parts[1] . '.' . $parts[2]; 200 } 201} 202