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