bda63fa3e0051ca0b47c5727889facab89003a26
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Service / CoreVersionService.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Install\Service;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use TYPO3\CMS\Core\Registry;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Utility\VersionNumberUtility;
22
23 /**
24 * Core version service
25 * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
26 */
27 class CoreVersionService
28 {
29 /**
30 * @var \TYPO3\CMS\Core\Registry
31 */
32 protected $registry;
33
34 /**
35 * Base URI for TYPO3 Version REST api
36 *
37 * @var string
38 */
39 protected $apiBaseUrl = 'https://get.typo3.org/v1/api/';
40
41 /**
42 * Initialize update URI
43 *
44 * @param Registry $registry Deprecated
45 */
46 public function __construct(Registry $registry = null)
47 {
48 if (null !== $registry) {
49 trigger_error(
50 'The constructor parameter $registry for CoreVersionService is deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0.',
51 E_USER_DEPRECATED
52 );
53 $this->registry = $registry;
54 } else {
55 $this->registry = GeneralUtility::makeInstance(Registry::class);
56 }
57 }
58
59 /**
60 * Development git checkout versions always end with '-dev'. They are
61 * not "released" as such and can not be updated.
62 *
63 * @return bool FALSE If some development version is installed
64 */
65 public function isInstalledVersionAReleasedVersion(): bool
66 {
67 $version = $this->getInstalledVersion();
68 return substr($version, -4) !== '-dev';
69 }
70
71 /**
72 * Get sha1 of a version from version matrix
73 *
74 * @param string $version A version to get sha1 of
75 * @return string sha1 of version
76 * @throws Exception\CoreVersionServiceException
77 */
78 public function getTarGzSha1OfVersion(string $version): string
79 {
80 $url = 'release/' . $version;
81 $result = $this->fetchFromRemote($url);
82
83 return $result['tar_package']['sha1sum'] ?? '';
84 }
85
86 /**
87 * Get current installed version number
88 *
89 * @return string
90 */
91 public function getInstalledVersion(): string
92 {
93 return VersionNumberUtility::getCurrentTypo3Version();
94 }
95
96 /**
97 * Checks if TYPO3 version (e.g. 6.2) is an actively maintained version
98 *
99 * @return bool TRUE if version is actively maintained
100 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
101 */
102 public function isVersionActivelyMaintained(): bool
103 {
104 $url = 'major/' . $this->getInstalledMajorVersion();
105 $result = $this->fetchFromRemote($url);
106
107 return !isset($result['maintained_until']) ||
108 (
109 new \DateTimeImmutable($result['maintained_until']) >=
110 new \DateTimeImmutable('now', new \DateTimeZone('UTC'))
111 );
112 }
113
114 /**
115 * Returns TRUE if a younger patch level release exists in version matrix.
116 *
117 * @return bool TRUE if younger patch release is exists
118 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
119 */
120 public function isYoungerPatchReleaseAvailable(): bool
121 {
122 return version_compare($this->getInstalledVersion(), $this->getYoungestPatchRelease()) === -1;
123 }
124
125 /**
126 * Returns TRUE if an upgrade from current version is security relevant
127 *
128 * @return bool TRUE if there is a pending security update
129 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
130 */
131 public function isUpdateSecurityRelevant(): bool
132 {
133 $url = 'major/' . $this->getInstalledMajorVersion() . '/release/latest/security';
134 $result = $this->fetchFromRemote($url);
135
136 if (isset($result['version'])) {
137 return version_compare($this->getInstalledVersion(), $result['version']) === -1;
138 }
139 return false;
140 }
141
142 /**
143 * Youngest patch release, e.g., 6.2.2
144 *
145 * @return string Version string of youngest patch level release
146 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
147 */
148 public function getYoungestPatchRelease(): string
149 {
150 $url = 'major/' . $this->getInstalledMajorVersion() . '/release/latest';
151 $result = $this->fetchFromRemote($url);
152 return $result['version'];
153 }
154
155 /**
156 * @param string $url
157 * @return array
158 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
159 */
160 protected function fetchFromRemote(string $url): array
161 {
162 $url = $this->apiBaseUrl . $url;
163 $json = GeneralUtility::getUrl($url);
164
165 if (!$json) {
166 $this->throwFetchException($url);
167 }
168 return json_decode($json, true);
169 }
170
171 /**
172 * Get 'major version' from installed version of TYPO3, e.g., '7' from '7.3.0'
173 *
174 * @return string For example 7
175 */
176 protected function getInstalledMajorVersion(): string
177 {
178 return $this->getMajorVersion($this->getInstalledVersion());
179 }
180
181 /**
182 * Get 'major version' of version, e.g., '7' from '7.3.0'
183 *
184 * @param string $version to check
185 * @return string Major version, e.g., '7'
186 */
187 protected function getMajorVersion(string $version): string
188 {
189 $explodedVersion = explode('.', $version);
190 return $explodedVersion[0];
191 }
192
193 /**
194 * Update version matrix from remote and store in registry
195 *
196 * @deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0 - use new REST API directly (see https://get.typo3.org/v1/api/doc)
197 * @throws Exception\RemoteFetchException
198 */
199 public function updateVersionMatrix(): void
200 {
201 trigger_error('Method updateVersionMatrix will be removed in TYPO3 v10.0, use new REST API directly (see https://get.typo3.org/v1/api/doc).', E_USER_DEPRECATED);
202 $url = 'https://get.typo3.org/json';
203 $versionJson = GeneralUtility::getUrl($url);
204 if (!$versionJson) {
205 $this->throwFetchException($url);
206 }
207 $versionArray = json_decode($versionJson, true);
208 $installedMajorVersion = (int)$this->getInstalledMajorVersion();
209
210 foreach ($versionArray as $versionNumber => $versionDetails) {
211 if (is_array($versionDetails) && (int)$this->getMajorVersion((string)$versionNumber) < $installedMajorVersion) {
212 unset($versionArray[$versionNumber]);
213 }
214 }
215
216 $this->registry->set('TYPO3.CMS.Install', 'coreVersionMatrix', $versionArray);
217 }
218
219 /**
220 * Youngest development patch release, e.g., 6.2.0alpha3 or 6.2-snapshot-20131004
221 *
222 * @deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0 - TYPO3 release cycles do not contain development releases anymore
223 * @return string
224 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
225 */
226 public function getYoungestPatchDevelopmentRelease(): string
227 {
228 trigger_error(
229 'Method getYoungestPatchDevelopmentRelease() is deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0, use getYoungestPatchRelease() instead.',
230 E_USER_DEPRECATED
231 );
232 return $this->getYoungestPatchRelease();
233 }
234
235 /**
236 * Returns TRUE if a younger patch level release exists in version matrix that may be a development release.
237 *
238 * @deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0 - TYPO3 release cycles do not contain development releases anymore
239 * @return bool TRUE if younger patch release is exists
240 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
241 */
242 public function isYoungerPatchDevelopmentReleaseAvailable(): bool
243 {
244 trigger_error(
245 'Method isYoungerPatchDevelopmentReleaseAvailable() is deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0, use isYoungerPatchReleaseAvailable() instead.',
246 E_USER_DEPRECATED
247 );
248 return $this->isYoungerPatchReleaseAvailable();
249 }
250
251 /**
252 * @deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0, use 'https://get.typo3.org' directly
253 * @return string
254 */
255 public function getDownloadBaseUrl(): string
256 {
257 trigger_error(
258 'Method getDownloadBaseUrl() is deprecated since TYPO3 v9 and will be removed in TYPO3 v10.0, use https://get.typo3.org directly.',
259 E_USER_DEPRECATED
260 );
261 return $this->apiBaseUrl;
262 }
263
264 /**
265 * Helper method to throw same exception in multiple places
266 *
267 * @param string $url
268 * @throws \TYPO3\CMS\Install\Service\Exception\RemoteFetchException
269 */
270 protected function throwFetchException(string $url): void
271 {
272 throw new Exception\RemoteFetchException(
273 'Fetching ' .
274 $url .
275 ' failed. Maybe this instance can not connect to the remote system properly.',
276 1380897593
277 );
278 }
279 }