a2d8666fdaed430322913346b429a27a97dc3c04
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Report / InstallStatusReport.php
1 <?php
2 namespace TYPO3\CMS\Install\Report;
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\Core\Environment;
18 use TYPO3\CMS\Core\Localization\LanguageService;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Install\Service\Exception;
21 use TYPO3\CMS\Reports\Status;
22
23 /**
24 * Provides an installation status report.
25 */
26 class InstallStatusReport implements \TYPO3\CMS\Reports\StatusProviderInterface
27 {
28 /**
29 * Compiles a collection of system status checks as a status report.
30 *
31 * @return Status[]
32 */
33 public function getStatus()
34 {
35 return [
36 'FileSystem' => $this->getFileSystemStatus(),
37 'RemainingUpdates' => $this->getRemainingUpdatesStatus(),
38 'NewVersion' => $this->getNewVersionStatus(),
39 ];
40 }
41
42 /**
43 * Checks for several directories being writable.
44 *
45 * @return Status Indicates status of the file system
46 */
47 protected function getFileSystemStatus()
48 {
49 $languageService = $this->getLanguageService();
50 $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_writable');
51 $message = '';
52 $severity = Status::OK;
53 // Requirement level
54 // -1 = not required, but if it exists may be writable or not
55 // 0 = not required, if it exists the dir should be writable
56 // 1 = required, doesn't have to be writable
57 // 2 = required, has to be writable
58 $varPath = Environment::getVarPath();
59 $sitePath = Environment::getPublicPath();
60 $rootPath = Environment::getProjectPath();
61 $checkWritable = [
62 $sitePath . '/typo3temp/' => 2,
63 $sitePath . '/typo3temp/assets/' => 2,
64 $sitePath . '/typo3temp/assets/compressed/' => 2,
65 // only needed when GraphicalFunctions is used
66 $sitePath . '/typo3temp/assets/images/' => 0,
67 // used in PageGenerator (inlineStyle2Temp) and Backend + Language JS files
68 $sitePath . '/typo3temp/assets/css/' => 2,
69 $sitePath . '/typo3temp/assets/js/' => 2,
70 // fallback storage of FAL
71 $sitePath . '/typo3temp/assets/_processed_/' => 0,
72 $varPath => 2,
73 $varPath . '/transient/' => 2,
74 $varPath . '/charset/' => 2,
75 $varPath . '/lock/' => 2,
76 $sitePath . '/typo3conf/' => 2,
77 $sitePath . '/typo3conf/ext/' => 0,
78 $sitePath . '/typo3conf/l10n/' => 0,
79 $sitePath . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] => -1,
80 $sitePath . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/' => 0,
81 ];
82
83 if ($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall']) {
84 $checkWritable[TYPO3_mainDir . 'ext/'] = -1;
85 }
86
87 foreach ($checkWritable as $path => $requirementLevel) {
88 $relPath = substr($path, strlen($rootPath) + 1);
89 if (!@is_dir($path)) {
90 // If the directory is missing, try to create it
91 GeneralUtility::mkdir($path);
92 }
93 if (!@is_dir($path)) {
94 if ($requirementLevel > 0) {
95 // directory is required
96 $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_missingDirectory');
97 $message .= sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryDoesNotExistCouldNotCreate'), $relPath) . '<br />';
98 $severity = Status::ERROR;
99 } else {
100 $message .= sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryDoesNotExist'), $relPath);
101 if ($requirementLevel == 0) {
102 $message .= ' ' . $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryShouldAlsoBeWritable');
103 }
104 $message .= '<br />';
105 if ($severity < Status::WARNING) {
106 $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_nonExistingDirectory');
107 $severity = Status::WARNING;
108 }
109 }
110 } else {
111 if (!is_writable($path)) {
112 switch ($requirementLevel) {
113 case 0:
114 $message .= sprintf(
115 $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryShouldBeWritable'),
116 $path
117 ) . '<br />';
118 if ($severity < Status::WARNING) {
119 $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_recommendedWritableDirectory');
120 $severity = Status::WARNING;
121 }
122 break;
123 case 2:
124 $value = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_requiredWritableDirectory');
125 $message .= sprintf(
126 $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_directoryMustBeWritable'),
127 $path
128 ) . '<br />';
129 $severity = Status::ERROR;
130 break;
131 default:
132 }
133 }
134 }
135 }
136 return GeneralUtility::makeInstance(Status::class, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_fileSystem'), $value, $message, $severity);
137 }
138
139 /**
140 * Checks if there are still updates to perform
141 *
142 * @return Status Represents whether the installation is completely updated yet
143 */
144 protected function getRemainingUpdatesStatus()
145 {
146 $languageService = $this->getLanguageService();
147 $value = $languageService->getLL('status_updateComplete');
148 $message = '';
149 $severity = Status::OK;
150 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
151 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
152 // check if there are update wizards left to perform
153 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
154 $versionAsInt = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
155 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
156 $updateObject = GeneralUtility::makeInstance($className, $identifier, $versionAsInt, null, $this);
157 if ($updateObject->shouldRenderWizard()) {
158 // at least one wizard was found
159 $value = $languageService->getLL('status_updateIncomplete');
160 $severity = Status::WARNING;
161 $url = (string)$uriBuilder->buildUriFromRoute('tools_toolsupgrade');
162 $message = sprintf($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:warning.install_update'), '<a href="' . htmlspecialchars($url) . '">', '</a>');
163 break;
164 }
165 }
166 }
167
168 return GeneralUtility::makeInstance(Status::class, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_remainingUpdates'), $value, $message, $severity);
169 }
170
171 /**
172 * Checks if there is a new minor TYPO3 version to update to.
173 *
174 * @return Status Represents whether there is a new version available online
175 */
176 protected function getNewVersionStatus()
177 {
178 $languageService = $this->getLanguageService();
179 /** @var \TYPO3\CMS\Install\Service\CoreVersionService $coreVersionService */
180 $coreVersionService = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Service\CoreVersionService::class);
181
182 // No updates for development versions
183 if (!$coreVersionService->isInstalledVersionAReleasedVersion()) {
184 return GeneralUtility::makeInstance(Status::class, 'TYPO3', TYPO3_version, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_isDevelopmentVersion'), Status::NOTICE);
185 }
186
187 // If fetching version matrix fails we can not do anything except print out the current version
188 try {
189 $coreVersionService->updateVersionMatrix();
190 } catch (Exception\RemoteFetchException $remoteFetchException) {
191 return GeneralUtility::makeInstance(Status::class, 'TYPO3', TYPO3_version, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_remoteFetchException'), Status::NOTICE);
192 }
193
194 try {
195 $isUpdateAvailable = $coreVersionService->isYoungerPatchReleaseAvailable();
196 $isMaintainedVersion = $coreVersionService->isVersionActivelyMaintained();
197 } catch (Exception\CoreVersionServiceException $coreVersionServiceException) {
198 return GeneralUtility::makeInstance(Status::class, 'TYPO3', TYPO3_version, $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_patchLevelNotFoundInReleaseMatrix'), Status::WARNING);
199 }
200
201 if (!$isUpdateAvailable && $isMaintainedVersion) {
202 // Everything is fine, working with the latest version
203 $message = '';
204 $status = Status::OK;
205 } elseif ($isUpdateAvailable) {
206 // There is an update available
207 $newVersion = $coreVersionService->getYoungestPatchRelease();
208 if ($coreVersionService->isUpdateSecurityRelevant()) {
209 $message = sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_newVersionSecurityRelevant'), $newVersion);
210 $status = Status::ERROR;
211 } else {
212 $message = sprintf($languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_newVersion'), $newVersion);
213 $status = Status::WARNING;
214 }
215 } else {
216 // Version is not maintained
217 $message = $languageService->sL('LLL:EXT:install/Resources/Private/Language/Report/locallang.xlf:status_versionOutdated');
218 $status = Status::ERROR;
219 }
220
221 return GeneralUtility::makeInstance(Status::class, 'TYPO3', TYPO3_version, $message, $status);
222 }
223
224 /**
225 * @return LanguageService
226 */
227 protected function getLanguageService()
228 {
229 return $GLOBALS['LANG'];
230 }
231 }