af4cd53aa85fab272a4845681468e0bea2f44a0a
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Service / CoreVersionService.php
1 <?php
2 namespace TYPO3\CMS\Install\Service;
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 use TYPO3\CMS\Core\Registry;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\VersionNumberUtility;
20
21 /**
22 * Core version service
23 */
24 class CoreVersionService
25 {
26 /**
27 * @var \TYPO3\CMS\Core\Registry
28 */
29 protected $registry;
30
31 /**
32 * Base URI for TYPO3 downloads
33 *
34 * @var string
35 */
36 protected $downloadBaseUri;
37
38 /**
39 * Initialize update URI
40 *
41 * @param Registry $registry
42 */
43 public function __construct(Registry $registry = null)
44 {
45 $this->downloadBaseUri = 'https://get.typo3.org/';
46 $this->registry = $registry ?: GeneralUtility::makeInstance(Registry::class);
47 }
48
49 /**
50 * @return mixed
51 */
52 public function getDownloadBaseUri()
53 {
54 return $this->downloadBaseUri;
55 }
56
57 /**
58 * Update version matrix from remote and store in registry
59 *
60 * @throws Exception\RemoteFetchException
61 */
62 public function updateVersionMatrix()
63 {
64 $versionArray = $this->fetchVersionMatrixFromRemote();
65 $installedMajorVersion = (int)$this->getInstalledMajorVersion();
66
67 foreach ($versionArray as $versionNumber => $versionDetails) {
68 if (is_array($versionDetails) && (int)$this->getMajorVersion($versionNumber) < $installedMajorVersion) {
69 unset($versionArray[$versionNumber]);
70 }
71 }
72
73 $this->registry->set('TYPO3.CMS.Install', 'coreVersionMatrix', $versionArray);
74 }
75
76 /**
77 * Development git checkout versions always end with '-dev'. They are
78 * not "released" as such and can not be updated.
79 *
80 * @return bool FALSE If some development version is installed
81 */
82 public function isInstalledVersionAReleasedVersion()
83 {
84 $version = $this->getInstalledVersion();
85 return substr($version, -4) !== '-dev';
86 }
87
88 /**
89 * Get sha1 of a version from version matrix
90 *
91 * @param string $version A version to get sha1 of
92 * @return string sha1 of version
93 * @throws Exception\CoreVersionServiceException
94 */
95 public function getTarGzSha1OfVersion($version)
96 {
97 $this->ensureVersionExistsInMatrix($version);
98
99 $majorVersion = $this->getMajorVersion($version);
100 $versionMatrix = $this->getVersionMatrix();
101
102 if (empty($versionMatrix[$majorVersion]['releases'][$version]['checksums']['tar']['sha1'])) {
103 throw new Exception\CoreVersionServiceException(
104 'Release sha1 of version ' . $version . ' not found in version matrix.'
105 . ' This is probably a bug on get.typo3.org.',
106 1381263173
107 );
108 }
109
110 return $versionMatrix[$majorVersion]['releases'][$version]['checksums']['tar']['sha1'];
111 }
112
113 /**
114 * Get current installed version number
115 *
116 * @return string
117 */
118 public function getInstalledVersion()
119 {
120 return VersionNumberUtility::getCurrentTypo3Version();
121 }
122
123 /**
124 * Checks if TYPO3 version (e.g. 6.2) is an actively maintained version
125 *
126 * @return bool TRUE if version is actively maintained
127 */
128 public function isVersionActivelyMaintained()
129 {
130 $majorVersion = $this->getInstalledMajorVersion();
131 $versionMatrix = $this->getVersionMatrix();
132 return (bool)$versionMatrix[$majorVersion]['active'];
133 }
134
135 /**
136 * Returns TRUE if a younger patch level release exists in version matrix.
137 *
138 * @return bool TRUE if younger patch release is exists
139 */
140 public function isYoungerPatchReleaseAvailable()
141 {
142 $version = $this->getInstalledVersion();
143 $youngestVersion = $this->getYoungestPatchRelease();
144 return $youngestVersion !== $version;
145 }
146
147 /**
148 * Returns TRUE if a younger patch level release exists in version matrix that may be a development release.
149 *
150 * @return bool TRUE if younger patch release is exists
151 */
152 public function isYoungerPatchDevelopmentReleaseAvailable()
153 {
154 $result = false;
155 $version = $this->getInstalledVersion();
156 $youngestVersion = $this->getYoungestPatchDevelopmentRelease();
157 if ($youngestVersion !== $version) {
158 $result = true;
159 }
160 return $result;
161 }
162
163 /**
164 * Returns TRUE if an upgrade from current version is security relevant
165 *
166 * @return bool TRUE if there is a pending security update
167 */
168 public function isUpdateSecurityRelevant()
169 {
170 $result = false;
171 $version = $this->getInstalledVersion();
172 $youngestVersion = $this->getYoungestReleaseByType(['security']);
173 if ($youngestVersion !== $version) {
174 $result = true;
175 }
176 return $result;
177 }
178
179 /**
180 * Youngest patch release, e.g., 6.2.2
181 *
182 * @return string Version string of youngest patch level release
183 */
184 public function getYoungestPatchRelease()
185 {
186 return $this->getYoungestReleaseByType(['release', 'security', 'regular']);
187 }
188
189 /**
190 * Youngest development patch release, e.g., 6.2.0alpha3 or 6.2-snapshot-20131004
191 *
192 * @return string
193 */
194 public function getYoungestPatchDevelopmentRelease()
195 {
196 return $this->getYoungestReleaseByType(['release', 'security', 'regular', 'development']);
197 }
198
199 /**
200 * Get youngest release version string.
201 * Returns same version number if no younger release was found.
202 *
203 * @param array $types List of allowed types: development, release, security, regular
204 * @throws Exception\CoreVersionServiceException
205 * @return string Youngest release, e.g., 7.2.0alpha3 or 7.3.0
206 */
207 protected function getYoungestReleaseByType(array $types)
208 {
209 $version = $this->getInstalledVersion();
210
211 $majorVersion = $this->getMajorVersion($version);
212 $versionMatrix = $this->getVersionMatrix();
213
214 $youngestRelease = $version;
215 $versionReleaseTimestamp = $this->getReleaseTimestampOfVersion($version);
216
217 $patchLevelVersions = $versionMatrix[$majorVersion]['releases'];
218 foreach ($patchLevelVersions as $aVersionNumber => $aVersionDetails) {
219 if (!array_key_exists('type', $aVersionDetails)) {
220 throw new Exception\CoreVersionServiceException(
221 'Release type of version ' . $aVersionNumber . ' not found in version matrix.'
222 . ' This is probably a bug on get.typo3.org.',
223 1380909029
224 );
225 }
226 $type = $aVersionDetails['type'];
227 $aVersionNumberReleaseTimestamp = $this->getReleaseTimestampOfVersion($aVersionNumber);
228 if (
229 $aVersionNumberReleaseTimestamp > $versionReleaseTimestamp
230 && in_array($type, $types)
231 ) {
232 $youngestRelease = $aVersionNumber;
233 $versionReleaseTimestamp = $aVersionNumberReleaseTimestamp;
234 }
235 }
236 return $youngestRelease;
237 }
238
239 /**
240 * Get 'major version' from installed version of TYPO3, e.g., '7' from '7.3.0'
241 *
242 * @return string For example 7
243 */
244 protected function getInstalledMajorVersion()
245 {
246 return $this->getMajorVersion($this->getInstalledVersion());
247 }
248
249 /**
250 * Get 'major version' of version, e.g., '7' from '7.3.0'
251 *
252 * @param string $version to check
253 * @return string Major version, e.g., '7'
254 */
255 protected function getMajorVersion($version)
256 {
257 $explodedVersion = explode('.', $version);
258 return $explodedVersion[0];
259 }
260
261 /**
262 * Get version matrix from registry
263 *
264 * @return array
265 * @throws Exception
266 */
267 protected function getVersionMatrix()
268 {
269 $versionMatrix = $this->registry->get('TYPO3.CMS.Install', 'coreVersionMatrix');
270 if (empty($versionMatrix) || !is_array($versionMatrix)) {
271 throw new Exception\CoreVersionServiceException(
272 'No version matrix found in registry, call updateVersionMatrix() first.',
273 1380898792
274 );
275 }
276 return $versionMatrix;
277 }
278
279 /**
280 * Get available version string from get.typo3.org
281 *
282 * @return array
283 * @throws Exception\RemoteFetchException
284 */
285 protected function fetchVersionMatrixFromRemote()
286 {
287 $url = $this->downloadBaseUri . 'json';
288 $versionJson = GeneralUtility::getUrl($url);
289 if (!$versionJson) {
290 throw new Exception\RemoteFetchException(
291 'Fetching ' . $url . ' failed. Maybe this instance can not connect to the remote system properly.',
292 1380897593
293 );
294 }
295 return json_decode($versionJson, true);
296 }
297
298 /**
299 * Returns release timestamp of a specific version
300 *
301 * @param $version String to check in version matrix, e.g., 7.2.0alpha3 or 7.3.0
302 * @throws Exception\CoreVersionServiceException
303 * @return int Timestamp of release
304 */
305 protected function getReleaseTimestampOfVersion($version)
306 {
307 $majorVersion = $this->getMajorVersion($version);
308 $versionMatrix = $this->getVersionMatrix();
309 $this->ensureVersionExistsInMatrix($version);
310 if (!array_key_exists('date', $versionMatrix[$majorVersion]['releases'][$version])) {
311 throw new Exception\CoreVersionServiceException(
312 'Release date of version ' . $version . ' not found in version matrix. This is probably a bug on get.typo3.org',
313 1380905853
314 );
315 }
316 $dateString = $versionMatrix[$majorVersion]['releases'][$version]['date'];
317 $date = new \DateTime($dateString);
318 return $date->getTimestamp();
319 }
320
321 /**
322 * Throws an exception if specified version does not exist in version matrix
323 *
324 * @param $version String to check in version matrix, e.g., 7.2.0alpha3 or 7.3.0
325 * @throws Exception\CoreVersionServiceException
326 */
327 protected function ensureVersionExistsInMatrix($version)
328 {
329 $majorVersion = $this->getMajorVersion($version);
330 $versionMatrix = $this->getVersionMatrix();
331 if (!array_key_exists($majorVersion, $versionMatrix)) {
332 throw new Exception\CoreVersionServiceException(
333 'Major release ' . $majorVersion . ' not found in version matrix.',
334 1380905851
335 );
336 }
337 if (!array_key_exists($version, $versionMatrix[$majorVersion]['releases'])) {
338 throw new Exception\CoreVersionServiceException(
339 'Patch level release ' . $version . ' not found in version matrix.',
340 1380905852
341 );
342 }
343 }
344 }