[CLEANUP] Code cleanup in ext:reports
[Packages/TYPO3.CMS.git] / typo3 / sysext / reports / Classes / Report / Status / ConfigurationStatus.php
1 <?php
2 namespace TYPO3\CMS\Reports\Report\Status;
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\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Database\DatabaseConnection;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Core\Messaging\FlashMessageService;
21 use TYPO3\CMS\Core\Registry;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Core\Utility\PathUtility;
24 use TYPO3\CMS\Lang\LanguageService;
25 use TYPO3\CMS\Reports\Status;
26 use TYPO3\CMS\Reports\StatusProviderInterface;
27
28 /**
29 * Performs some checks about the install tool protection status
30 */
31 class ConfigurationStatus implements StatusProviderInterface
32 {
33 /**
34 * 10MB
35 *
36 * @var int
37 */
38 protected $deprecationLogFileSizeWarningThreshold = 10485760;
39
40 /**
41 * 100MB
42 *
43 * @var int
44 */
45 protected $deprecationLogFileSizeErrorThreshold = 104857600;
46
47 /**
48 * Backpath to the typo3 main directory
49 *
50 * @var string
51 */
52 protected $backPath = '../';
53
54 /**
55 * Determines the Install Tool's status, mainly concerning its protection.
56 *
57 * @return array List of statuses
58 */
59 public function getStatus()
60 {
61 $this->executeAdminCommand();
62 $statuses = array(
63 'emptyReferenceIndex' => $this->getReferenceIndexStatus(),
64 'deprecationLog' => $this->getDeprecationLogStatus()
65 );
66 if ($this->isMemcachedUsed()) {
67 $statuses['memcachedConnection'] = $this->getMemcachedConnectionStatus();
68 }
69 if (TYPO3_OS !== 'WIN') {
70 $statuses['createdFilesWorldWritable'] = $this->getCreatedFilesWorldWritableStatus();
71 $statuses['createdDirectoriesWorldWritable'] = $this->getCreatedDirectoriesWorldWritableStatus();
72 }
73 return $statuses;
74 }
75
76 /**
77 * Checks if sys_refindex is empty.
78 *
79 * @return \TYPO3\CMS\Reports\Status An object representing whether the reference index is empty or not
80 */
81 protected function getReferenceIndexStatus()
82 {
83 $value = $this->getLanguageService()->getLL('status_ok');
84 $message = '';
85 $severity = Status::OK;
86 $count = $this->getDatabaseConnection()->exec_SELECTcountRows('*', 'sys_refindex');
87 $registry = GeneralUtility::makeInstance(Registry::class);
88 $lastRefIndexUpdate = $registry->get('core', 'sys_refindex_lastUpdate');
89 if (!$count && $lastRefIndexUpdate) {
90 $value = $this->getLanguageService()->getLL('status_empty');
91 $severity = Status::WARNING;
92 $url = BackendUtility::getModuleUrl('system_dbint') . '&id=0&SET[function]=refindex';
93 $message = sprintf($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:warning.backend_reference_index'), '<a href="' . htmlspecialchars($url) . '">', '</a>', BackendUtility::dateTime($lastRefIndexUpdate));
94 }
95 return GeneralUtility::makeInstance(Status::class, $this->getLanguageService()->getLL('status_referenceIndex'), $value, $message, $severity);
96 }
97
98 /**
99 * Checks whether memcached is configured, if that's the case we assume it's also used.
100 *
101 * @return bool TRUE if memcached is used, FALSE otherwise.
102 */
103 protected function isMemcachedUsed()
104 {
105 $memcachedUsed = false;
106 $memcachedServers = $this->getConfiguredMemcachedServers();
107 if (!empty($memcachedServers)) {
108 $memcachedUsed = true;
109 }
110 return $memcachedUsed;
111 }
112
113 /**
114 * Gets the configured memcached server connections.
115 *
116 * @return array An array of configured memcached server connections.
117 */
118 protected function getConfiguredMemcachedServers()
119 {
120 $memcachedServers = array();
121 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'])) {
122 foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] as $table => $conf) {
123 if (is_array($conf)) {
124 foreach ($conf as $key => $value) {
125 if (!is_array($value) && $value === \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend::class) {
126 $memcachedServers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$table]['options']['servers'];
127 break;
128 }
129 }
130 }
131 }
132 }
133 return $memcachedServers;
134 }
135
136 /**
137 * Checks whether TYPO3 can connect to the configured memcached servers.
138 *
139 * @return \TYPO3\CMS\Reports\Status An object representing whether TYPO3 can connect to the configured memcached servers
140 */
141 protected function getMemcachedConnectionStatus()
142 {
143 $value = $this->getLanguageService()->getLL('status_ok');
144 $message = '';
145 $severity = Status::OK;
146 $failedConnections = array();
147 $defaultMemcachedPort = ini_get('memcache.default_port');
148 $memcachedServers = $this->getConfiguredMemcachedServers();
149 if (function_exists('memcache_connect') && is_array($memcachedServers)) {
150 foreach ($memcachedServers as $testServer) {
151 $configuredServer = $testServer;
152 if (substr($testServer, 0, 7) == 'unix://') {
153 $host = $testServer;
154 $port = 0;
155 } else {
156 if (substr($testServer, 0, 6) === 'tcp://') {
157 $testServer = substr($testServer, 6);
158 }
159 if (strstr($testServer, ':') !== false) {
160 list($host, $port) = explode(':', $testServer, 2);
161 } else {
162 $host = $testServer;
163 $port = $defaultMemcachedPort;
164 }
165 }
166 $memcachedConnection = @memcache_connect($host, $port);
167 if ($memcachedConnection != null) {
168 memcache_close($memcachedConnection);
169 } else {
170 $failedConnections[] = $configuredServer;
171 }
172 }
173 }
174 if (!empty($failedConnections)) {
175 $value = $this->getLanguageService()->getLL('status_connectionFailed');
176 $severity = Status::WARNING;
177 $message = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:warning.memcache_not_usable') . '<br /><br />' . '<ul><li>' . implode('</li><li>', $failedConnections) . '</li></ul>';
178 }
179 return GeneralUtility::makeInstance(Status::class, $this->getLanguageService()->getLL('status_memcachedConfiguration'), $value, $message, $severity);
180 }
181
182 /**
183 * Provides status information on the deprecation log, whether it's enabled
184 * and if so whether certain limits in file size are reached.
185 *
186 * @return \TYPO3\CMS\Reports\Status The deprecation log status.
187 */
188 protected function getDeprecationLogStatus()
189 {
190 $title = $this->getLanguageService()->getLL('status_configuration_DeprecationLog');
191 $value = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:disabled');
192 $message = '';
193 $severity = Status::OK;
194 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) {
195 $value = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:enabled');
196 $message = '<p>' . $this->getLanguageService()->getLL('status_configuration_DeprecationLogEnabled') . '</p>';
197 $severity = Status::NOTICE;
198 $logFile = GeneralUtility::getDeprecationLogFileName();
199 $logFileSize = 0;
200 if (@file_exists($logFile)) {
201 $logFileSize = filesize($logFile);
202 $message .= '<p>' . sprintf($this->getLanguageService()->getLL('status_configuration_DeprecationLogFile'), $this->getDeprecationLogFileLink()) . '</p>';
203 $removeDeprecationLogFileUrl = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL') . '&amp;adminCmd=removeDeprecationLogFile';
204 $message .= '<p>' . sprintf($this->getLanguageService()->getLL('status_configuration_DeprecationLogSize'), GeneralUtility::formatSize($logFileSize)) . ' <a href="' . $removeDeprecationLogFileUrl . '">' . $this->getLanguageService()->getLL('status_configuration_DeprecationLogDeleteLink') . '</a></p>';
205 }
206 if ($logFileSize > $this->deprecationLogFileSizeWarningThreshold) {
207 $severity = Status::WARNING;
208 }
209 if ($logFileSize > $this->deprecationLogFileSizeErrorThreshold) {
210 $severity = Status::ERROR;
211 }
212 }
213 return GeneralUtility::makeInstance(Status::class, $title, $value, $message, $severity);
214 }
215
216 /**
217 * Warning, if fileCreateMask has write bit for 'others' set.
218 *
219 * @return \TYPO3\CMS\Reports\Status The writable status for 'others'
220 */
221 protected function getCreatedFilesWorldWritableStatus()
222 {
223 $value = $this->getLanguageService()->getLL('status_ok');
224 $message = '';
225 $severity = Status::OK;
226 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] % 10 & 2) {
227 $value = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'];
228 $severity = Status::WARNING;
229 $message = $this->getLanguageService()->getLL('status_CreatedFilePermissions.writable');
230 }
231 return GeneralUtility::makeInstance(Status::class, $this->getLanguageService()->getLL('status_CreatedFilePermissions'), $value, $message, $severity);
232 }
233
234 /**
235 * Warning, if folderCreateMask has write bit for 'others' set.
236 *
237 * @return \TYPO3\CMS\Reports\Status The writable status for 'others'
238 */
239 protected function getCreatedDirectoriesWorldWritableStatus()
240 {
241 $value = $this->getLanguageService()->getLL('status_ok');
242 $message = '';
243 $severity = Status::OK;
244 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] % 10 & 2) {
245 $value = $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'];
246 $severity = Status::WARNING;
247 $message = $this->getLanguageService()->getLL('status_CreatedDirectoryPermissions.writable');
248 }
249 return GeneralUtility::makeInstance(Status::class, $this->getLanguageService()->getLL('status_CreatedDirectoryPermissions'), $value, $message, $severity);
250 }
251
252 /**
253 * Creates a link to the deprecation log file with the absolute path as the
254 * link text.
255 *
256 * @return string Link to the deprecation log file
257 */
258 protected function getDeprecationLogFileLink()
259 {
260 $logFile = GeneralUtility::getDeprecationLogFileName();
261 $relativePath = GeneralUtility::resolveBackPath($this->backPath . PathUtility::stripPathSitePrefix($logFile));
262 $link = '<a href="' . $relativePath . '">' . $logFile . '</a>';
263 return $link;
264 }
265
266 /**
267 * Executes admin commands.
268 *
269 * Currently implemented commands are:
270 * - Remove deprecation log file
271 *
272 * @return void
273 */
274 protected function executeAdminCommand()
275 {
276 $command = GeneralUtility::_GET('adminCmd');
277 switch ($command) {
278 case 'removeDeprecationLogFile':
279 self::removeDeprecationLogFile();
280 break;
281 default:
282 // intentionally left blank
283 }
284 }
285
286 /**
287 * Remove deprecation log file.
288 *
289 * @return void
290 */
291 protected static function removeDeprecationLogFile()
292 {
293 if (@unlink(GeneralUtility::getDeprecationLogFileName())) {
294 $message = $GLOBALS['LANG']->getLL('status_configuration_DeprecationLogDeletedSuccessful');
295 $severity = FlashMessage::OK;
296 } else {
297 $message = $GLOBALS['LANG']->getLL('status_configuration_DeprecationLogDeletionFailed');
298 $severity = FlashMessage::ERROR;
299 }
300 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $message, '', $severity, true);
301 /** @var FlashMessageService $flashMessageService */
302 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
303 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue $defaultFlashMessageQueue */
304 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
305 $defaultFlashMessageQueue->enqueue($flashMessage);
306 }
307
308 /**
309 * @return LanguageService
310 */
311 protected function getLanguageService()
312 {
313 return $GLOBALS['LANG'];
314 }
315
316 /**
317 * @return DatabaseConnection
318 */
319 protected function getDatabaseConnection()
320 {
321 return $GLOBALS['TYPO3_DB'];
322 }
323 }