‪TYPO3CMS  10.4
InstallStatusReport.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
23 use TYPO3\CMS\Install\Service\CoreVersionService;
28 
34 {
35  protected const ‪WRAP_FLAT = 1;
36  protected const ‪WRAP_NESTED = 2;
37 
38  protected ‪$useMarkup;
39 
40  public function ‪__construct(bool ‪$useMarkup = true)
41  {
42  $this->useMarkup = ‪$useMarkup;
43  }
44 
50  public function ‪getStatus()
51  {
52  return [
53  'FileSystem' => $this->‪getFileSystemStatus(),
54  'RemainingUpdates' => $this->‪getRemainingUpdatesStatus(),
55  'NewVersion' => $this->‪getNewVersionStatus(),
56  ];
57  }
58 
64  protected function ‪getFileSystemStatus()
65  {
66  $languageService = $this->‪getLanguageService();
67  $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_writable');
68  $message = '';
69  $severity = ‪Status::OK;
70  // Requirement level
71  // -1 = not required, but if it exists may be writable or not
72  // 0 = not required, if it exists the dir should be writable
73  // 1 = required, doesn't have to be writable
74  // 2 = required, has to be writable
75  $varPath = ‪Environment::getVarPath();
76  $sitePath = ‪Environment::getPublicPath();
77  $rootPath = ‪Environment::getProjectPath();
78  $checkWritable = [
79  $sitePath . '/typo3temp/' => 2,
80  $sitePath . '/typo3temp/assets/' => 2,
81  $sitePath . '/typo3temp/assets/compressed/' => 2,
82  // only needed when GraphicalFunctions is used
83  $sitePath . '/typo3temp/assets/images/' => 0,
84  // used in PageGenerator (inlineStyle2Temp) and Backend + Language JS files
85  $sitePath . '/typo3temp/assets/css/' => 2,
86  $sitePath . '/typo3temp/assets/js/' => 2,
87  // fallback storage of FAL
88  $sitePath . '/typo3temp/assets/_processed_/' => 0,
89  $varPath => 2,
90  $varPath . '/transient/' => 2,
91  $varPath . '/charset/' => 2,
92  $varPath . '/lock/' => 2,
93  $sitePath . '/typo3conf/' => 2,
95  $sitePath . '/' . ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] => -1,
96  $sitePath . '/' . ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/' => 0,
97  ];
98 
99  // Check for writable extension folder files in non-composer mode only
101  $checkWritable[‪Environment::getExtensionsPath()] = 0;
102  if (‪$GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall']) {
103  $checkWritable[‪Environment::getBackendPath() . '/ext/'] = -1;
104  }
105  }
106 
107  foreach ($checkWritable as $path => $requirementLevel) {
108  $relPath = substr($path, strlen($rootPath) + 1);
109  if (!@is_dir($path)) {
110  // If the directory is missing, try to create it
112  }
113  if (!@is_dir($path)) {
114  if ($requirementLevel > 0) {
115  // directory is required
116  $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_missingDirectory');
117  $message .= sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryDoesNotExistCouldNotCreate'), $relPath) . '<br />';
118  $severity = ‪Status::ERROR;
119  } else {
120  $message .= sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryDoesNotExist'), $relPath);
121  if ($requirementLevel == 0) {
122  $message .= ' ' . $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryShouldAlsoBeWritable');
123  }
124  $message .= '<br />';
125  if ($severity < ‪Status::WARNING) {
126  $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_nonExistingDirectory');
127  $severity = ‪Status::WARNING;
128  }
129  }
130  } else {
131  if (!is_writable($path)) {
132  switch ($requirementLevel) {
133  case 0:
134  $message .= sprintf(
135  $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryShouldBeWritable'),
136  $path
137  ) . '<br />';
138  if ($severity < ‪Status::WARNING) {
139  $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_recommendedWritableDirectory');
140  $severity = ‪Status::WARNING;
141  }
142  break;
143  case 2:
144  $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_requiredWritableDirectory');
145  $message .= sprintf(
146  $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryMustBeWritable'),
147  $path
148  ) . '<br />';
149  $severity = ‪Status::ERROR;
150  break;
151  default:
152  }
153  }
154  }
155  }
156  return GeneralUtility::makeInstance(Status::class, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_fileSystem'), $value, $message, $severity);
157  }
158 
167  protected function ‪getIncompleteWizards(): array
168  {
169  $upgradeWizardsService = GeneralUtility::makeInstance(UpgradeWizardsService::class);
170  $incompleteWizards = $upgradeWizardsService->getUpgradeWizardsList();
171  $incompleteWizards = array_filter(
172  $incompleteWizards,
173  function ($wizard) {
174  return $wizard['shouldRenderWizard'];
175  }
176  );
177  return $incompleteWizards;
178  }
179 
185  protected function ‪getRemainingUpdatesStatus()
186  {
187  $languageService = $this->‪getLanguageService();
188  $value = $languageService->getLL('status_updateComplete');
189  $message = '';
190  $severity = ‪Status::OK;
192  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
193  // check if there are update wizards left to perform
194  $incompleteWizards = $this->‪getIncompleteWizards();
195  if (count($incompleteWizards)) {
196  // At least one incomplete wizard was found
197  $value = $languageService->getLL('status_updateIncomplete');
198  $severity = ‪Status::WARNING;
199  $url = (string)$uriBuilder->buildUriFromRoute('tools_toolsupgrade');
200  $message = sprintf($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.install_update'), '<a href="' . htmlspecialchars($url) . '">', '</a>');
201  }
202 
203  return GeneralUtility::makeInstance(Status::class, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_remainingUpdates'), $value, $message, $severity);
204  }
205 
211  protected function ‪getNewVersionStatus()
212  {
213  $typoVersion = GeneralUtility::makeInstance(Typo3Version::class);
214  $languageService = $this->‪getLanguageService();
216  $coreVersionService = GeneralUtility::makeInstance(CoreVersionService::class);
217 
218  // No updates for development versions
219  if (!$coreVersionService->isInstalledVersionAReleasedVersion()) {
220  return GeneralUtility::makeInstance(Status::class, 'TYPO3', $typoVersion->getVersion(), $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_isDevelopmentVersion'), ‪Status::NOTICE);
221  }
222 
223  try {
224  $versionMaintenanceWindow = $coreVersionService->getMaintenanceWindow();
225  } catch (‪RemoteFetchException $remoteFetchException) {
226  return GeneralUtility::makeInstance(
227  Status::class,
228  'TYPO3',
229  $typoVersion->getVersion(),
230  $languageService->sL(
231  'LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_remoteFetchException'
232  ),
234  );
235  }
236 
237  if (!$versionMaintenanceWindow->isSupportedByCommunity() && !$versionMaintenanceWindow->isSupportedByElts()) {
238  // Version is not maintained
239  $message = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_versionOutdated');
240  $status = ‪Status::ERROR;
241  } else {
242  $message = '';
243  $status = ‪Status::OK;
244 
245  // There is an update available
246  $availableReleases = [];
247  $latestRelease = $coreVersionService->getYoungestPatchRelease();
248  $isCurrentVersionElts = $coreVersionService->isCurrentInstalledVersionElts();
249 
250  if ($coreVersionService->isPatchReleaseSuitableForUpdate($latestRelease)) {
251  $availableReleases[] = $latestRelease;
252  }
253 
254  if (!$versionMaintenanceWindow->isSupportedByCommunity()) {
255  if ($latestRelease->isElts()) {
256  $latestCommunityDrivenRelease = $coreVersionService->getYoungestCommunityPatchRelease();
257  if ($coreVersionService->isPatchReleaseSuitableForUpdate($latestCommunityDrivenRelease)) {
258  $availableReleases[] = $latestCommunityDrivenRelease;
259  }
260  } elseif (!$isCurrentVersionElts) {
261  // Inform user about ELTS being available soon if:
262  // - regular support ran out
263  // - the current installed version is no ELTS
264  // - no ELTS update was released, yet
265  $message = sprintf(
266  $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_elts_information'),
267  TYPO3_version,
268  '<a href="https://typo3.com/elts" target="_blank" rel="noopener">https://typo3.com/elts</a>'
269  );
270  $status = ‪Status::WARNING;
271  }
272  }
273 
274  if ($availableReleases !== []) {
275  $messages = [];
276  $status = ‪Status::WARNING;
277  foreach ($availableReleases as $availableRelease) {
278  $versionString = $availableRelease->getVersion();
279  if ($availableRelease->isElts()) {
280  $versionString .= ' ELTS';
281  }
282  if ($coreVersionService->isUpdateSecurityRelevant($availableRelease)) {
283  $status = ‪Status::ERROR;
284  $updateMessage = sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_newVersionSecurityRelevant'), $versionString);
285  } else {
286  $updateMessage = sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_newVersion'), $versionString);
287  }
288 
289  if ($availableRelease->isElts()) {
290  if ($isCurrentVersionElts) {
291  $updateMessage .= ' ' . sprintf(
292  $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_elts_download'),
293  '<a href="https://my.typo3.org" target="_blank" rel="noopener">my.typo3.org</a>'
294  );
295  } else {
296  $updateMessage .= ' ' . sprintf(
297  $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_elts_subscribe'),
298  $coreVersionService->getInstalledVersion(),
299  '<a href="https://typo3.com/elts" target="_blank" rel="noopener">https://typo3.com/elts</a>'
300  );
301  }
302  }
303  $messages[] = $updateMessage;
304  }
305  $message = $this->‪wrapList($messages, count($messages) > 1 ? self::WRAP_NESTED : self::WRAP_FLAT);
306  }
307  }
308 
309  return GeneralUtility::makeInstance(Status::class, 'TYPO3', $typoVersion->getVersion(), $message, $status);
310  }
311 
312  protected function ‪wrapList(array $items, int $style): string
313  {
314  if (!$this->useMarkup) {
315  return implode(', ', $items);
316  }
317  if ($style === self::WRAP_NESTED) {
318  return sprintf(
319  '<ul>%s</ul>',
320  implode('', $this->‪wrapItems($items, '<li>', '</li>'))
321  );
322  }
323  return sprintf(
324  '<p>%s</p>',
325  implode('', $this->‪wrapItems($items, '<br>', ''))
326  );
327  }
328 
329  protected function ‪wrapItems(array $items, string $before, string $after): array
330  {
331  return array_map(
332  static function (string $item) use ($before, $after): string {
333  return $before . $item . $after;
334  },
335  array_filter($items)
336  );
337  }
338 
342  protected function ‪getLanguageService()
343  {
344  return ‪$GLOBALS['LANG'];
345  }
346 }
‪TYPO3\CMS\Install\Report\InstallStatusReport\WRAP_FLAT
‪const WRAP_FLAT
Definition: InstallStatusReport.php:35
‪TYPO3\CMS\Reports\StatusProviderInterface
Definition: StatusProviderInterface.php:22
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Core\Environment\getLabelsPath
‪static string getLabelsPath()
Definition: Environment.php:236
‪TYPO3\CMS\Core\Information\Typo3Version
Definition: Typo3Version.php:21
‪TYPO3\CMS\Reports\Status\NOTICE
‪const NOTICE
Definition: Status.php:25
‪TYPO3\CMS\Install\Report\InstallStatusReport
Definition: InstallStatusReport.php:34
‪TYPO3\CMS\Reports\Status\ERROR
‪const ERROR
Definition: Status.php:29
‪TYPO3\CMS\Install\Report
Definition: EnvironmentStatusReport.php:16
‪TYPO3\CMS\Install\Report\InstallStatusReport\getFileSystemStatus
‪Status getFileSystemStatus()
Definition: InstallStatusReport.php:64
‪TYPO3\CMS\Install\Report\InstallStatusReport\__construct
‪__construct(bool $useMarkup=true)
Definition: InstallStatusReport.php:40
‪TYPO3\CMS\Install\Report\InstallStatusReport\getNewVersionStatus
‪Status getNewVersionStatus()
Definition: InstallStatusReport.php:211
‪TYPO3\CMS\Install\Service\UpgradeWizardsService
Definition: UpgradeWizardsService.php:43
‪TYPO3\CMS\Reports\Status\OK
‪const OK
Definition: Status.php:27
‪TYPO3\CMS\Reports\Status
Definition: Status.php:24
‪TYPO3\CMS\Install\Report\InstallStatusReport\getIncompleteWizards
‪array getIncompleteWizards()
Definition: InstallStatusReport.php:167
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:169
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:38
‪TYPO3\CMS\Install\Report\InstallStatusReport\wrapItems
‪wrapItems(array $items, string $before, string $after)
Definition: InstallStatusReport.php:329
‪TYPO3\CMS\Core\Core\Environment\getBackendPath
‪static string getBackendPath()
Definition: Environment.php:250
‪TYPO3\CMS\Reports\Status\WARNING
‪const WARNING
Definition: Status.php:28
‪TYPO3\CMS\Install\Service\Exception\RemoteFetchException
Definition: RemoteFetchException.php:24
‪TYPO3\CMS\Install\Report\InstallStatusReport\wrapList
‪wrapList(array $items, int $style)
Definition: InstallStatusReport.php:312
‪TYPO3\CMS\Install\Report\InstallStatusReport\getStatus
‪Status[] getStatus()
Definition: InstallStatusReport.php:50
‪TYPO3\CMS\Install\Report\InstallStatusReport\getRemainingUpdatesStatus
‪Status getRemainingUpdatesStatus()
Definition: InstallStatusReport.php:185
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static bool isComposerMode()
Definition: Environment.php:144
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Install\Report\InstallStatusReport\getLanguageService
‪LanguageService getLanguageService()
Definition: InstallStatusReport.php:342
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir
‪static bool mkdir($newFolder)
Definition: GeneralUtility.php:2005
‪TYPO3\CMS\Install\Report\InstallStatusReport\$useMarkup
‪$useMarkup
Definition: InstallStatusReport.php:38
‪TYPO3\CMS\Install\Report\InstallStatusReport\WRAP_NESTED
‪const WRAP_NESTED
Definition: InstallStatusReport.php:36
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:192
‪TYPO3\CMS\Core\Core\Environment\getExtensionsPath
‪static string getExtensionsPath()
Definition: Environment.php:271