9c385144937aa2a07108c7d20cce20e50cbab87d
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Backend / ToolbarItems / SystemInformationToolbarItem.php
1 <?php
2 namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
20 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Core\Bootstrap;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Imaging\Icon;
25 use TYPO3\CMS\Core\Imaging\IconFactory;
26 use TYPO3\CMS\Core\Page\PageRenderer;
27 use TYPO3\CMS\Core\Utility\CommandUtility;
28 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
29 use TYPO3\CMS\Core\Utility\GeneralUtility;
30 use TYPO3\CMS\Core\Utility\StringUtility;
31 use TYPO3\CMS\Fluid\View\StandaloneView;
32
33 /**
34 * Render system info toolbar item
35 */
36 class SystemInformationToolbarItem implements ToolbarItemInterface
37 {
38 /**
39 * @var StandaloneView
40 */
41 protected $standaloneView = null;
42
43 /**
44 * Template file for the dropdown menu
45 */
46 const TOOLBAR_MENU_TEMPLATE = 'SystemInformation.html';
47
48 /**
49 * Number displayed as badge on the dropdown trigger
50 *
51 * @var int
52 */
53 protected $totalCount = 0;
54
55 /**
56 * Holds the highest severity
57 *
58 * @var InformationStatus
59 */
60 protected $highestSeverity;
61
62 /**
63 * The CSS class for the badge
64 *
65 * @var string
66 */
67 protected $severityBadgeClass = '';
68
69 /**
70 * @var array
71 */
72 protected $systemInformation = array();
73
74 /**
75 * @var array
76 */
77 protected $systemMessages = array();
78
79 /**
80 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
81 */
82 protected $signalSlotDispatcher = null;
83
84 /**
85 * @var IconFactory
86 */
87 protected $iconFactory;
88
89 /**
90 * @var int
91 */
92 protected $maximumCountInBadge = 99;
93
94 /**
95 * Constructor
96 */
97 public function __construct()
98 {
99 if (!$this->checkAccess()) {
100 return;
101 }
102 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
103
104 $extPath = ExtensionManagementUtility::extPath('backend');
105 /* @var $view StandaloneView */
106 $this->standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
107 $this->standaloneView->setTemplatePathAndFilename($extPath . 'Resources/Private/Templates/ToolbarMenu/' . static::TOOLBAR_MENU_TEMPLATE);
108
109 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu');
110
111 $this->highestSeverity = InformationStatus::cast(InformationStatus::STATUS_INFO);
112 }
113
114 /**
115 * Collect the information for the menu
116 */
117 protected function collectInformation()
118 {
119 $this->getWebServer();
120 $this->getPhpVersion();
121 $this->getDatabase();
122 $this->getApplicationContext();
123 $this->getComposerMode();
124 $this->getGitRevision();
125 $this->getOperatingSystem();
126
127 $this->emitGetSystemInformation();
128 $this->emitLoadMessages();
129
130 $this->severityBadgeClass = !$this->highestSeverity->equals(InformationStatus::STATUS_NOTICE) ? 'badge-' . (string)$this->highestSeverity : '';
131 }
132
133 /**
134 * Renders the menu for AJAX calls
135 *
136 * @param ServerRequestInterface $request
137 * @param ResponseInterface $response
138 * @return ResponseInterface
139 */
140 public function renderMenuAction(ServerRequestInterface $request, ResponseInterface $response)
141 {
142 $this->collectInformation();
143
144 $response->getBody()->write($this->getDropDown());
145 $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
146 return $response;
147 }
148
149 /**
150 * Gets the PHP version
151 *
152 * @return void
153 */
154 protected function getPhpVersion()
155 {
156 $this->systemInformation[] = array(
157 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.phpversion')),
158 'value' => PHP_VERSION,
159 'icon' => $this->iconFactory->getIcon('sysinfo-php-version', Icon::SIZE_SMALL)->render()
160 );
161 }
162
163 /**
164 * Get the database info
165 *
166 * @return void
167 */
168 protected function getDatabase()
169 {
170 $this->systemInformation[] = array(
171 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.database')),
172 'value' => GeneralUtility::makeInstance(ConnectionPool::class)
173 ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME)
174 ->getServerVersion(),
175 'icon' => $this->iconFactory->getIcon('sysinfo-database', Icon::SIZE_SMALL)->render()
176 );
177 }
178
179 /**
180 * Gets the application context
181 *
182 * @return void
183 */
184 protected function getApplicationContext()
185 {
186 $applicationContext = GeneralUtility::getApplicationContext();
187 $this->systemInformation[] = array(
188 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.applicationcontext')),
189 'value' => (string)$applicationContext,
190 'status' => $applicationContext->isProduction() ? InformationStatus::STATUS_OK : InformationStatus::STATUS_WARNING,
191 'icon' => $this->iconFactory->getIcon('sysinfo-application-context', Icon::SIZE_SMALL)->render()
192 );
193 }
194
195 /**
196 * Adds the information if the Composer mode is enabled or disabled to the displayed system information
197 */
198 protected function getComposerMode()
199 {
200 if (!Bootstrap::usesComposerClassLoading()) {
201 return;
202 }
203
204 $languageService = $this->getLanguageService();
205 $this->systemInformation[] = array(
206 'title' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.composerMode')),
207 'value' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.enabled')),
208 'icon' => $this->iconFactory->getIcon('sysinfo-composer-mode', Icon::SIZE_SMALL)->render()
209 );
210 }
211
212 /**
213 * Gets the current GIT revision and branch
214 *
215 * @return void
216 */
217 protected function getGitRevision()
218 {
219 if (!StringUtility::endsWith(TYPO3_version, '-dev') || \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::isFunctionDisabled('exec')) {
220 return;
221 }
222 // check if git exists
223 CommandUtility::exec('git --version', $_, $returnCode);
224 if ((int)$returnCode !== 0) {
225 // git is not available
226 return;
227 }
228
229 $revision = trim(CommandUtility::exec('git rev-parse --short HEAD'));
230 $branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD'));
231 if (!empty($revision) && !empty($branch)) {
232 $this->systemInformation[] = array(
233 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.gitrevision')),
234 'value' => sprintf('%s [%s]', $revision, $branch),
235 'icon' => $this->iconFactory->getIcon('sysinfo-git', Icon::SIZE_SMALL)->render()
236 );
237 }
238 }
239
240 /**
241 * Gets the system kernel and version
242 *
243 * @return void
244 */
245 protected function getOperatingSystem()
246 {
247 $kernelName = php_uname('s');
248 switch (strtolower($kernelName)) {
249 case 'linux':
250 $icon = 'linux';
251 break;
252 case 'darwin':
253 $icon = 'apple';
254 break;
255 default:
256 $icon = 'windows';
257 }
258 $this->systemInformation[] = array(
259 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.operatingsystem')),
260 'value' => $kernelName . ' ' . php_uname('r'),
261 'icon' => $this->iconFactory->getIcon('sysinfo-os-' . $icon, Icon::SIZE_SMALL)->render()
262 );
263 }
264
265 /**
266 * Gets the webserver software
267 */
268 protected function getWebServer()
269 {
270 $this->systemInformation[] = array(
271 'title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.webserver')),
272 'value' => htmlspecialchars($_SERVER['SERVER_SOFTWARE']),
273 'icon' => $this->iconFactory->getIcon('sysinfo-webserver', Icon::SIZE_SMALL)->render()
274 );
275 }
276
277 /**
278 * Emits the "getSystemInformation" signal
279 *
280 * @return void
281 */
282 protected function emitGetSystemInformation()
283 {
284 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'getSystemInformation', array($this));
285 }
286
287 /**
288 * Emits the "loadMessages" signal
289 *
290 * @return void
291 */
292 protected function emitLoadMessages()
293 {
294 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'loadMessages', array($this));
295 }
296
297 /**
298 * Add a system message.
299 * This is a callback method for signal receivers.
300 *
301 * @param string $text The text to be displayed
302 * @param string $status The status of this system message
303 * @param int $count Will be added to the total count
304 * @param string $module The associated module
305 */
306 public function addSystemMessage($text, $status = InformationStatus::STATUS_OK, $count = 0, $module = '')
307 {
308 $this->totalCount += (int)$count;
309
310 /** @var InformationStatus $messageSeverity */
311 $messageSeverity = InformationStatus::cast($status);
312 // define the severity for the badge
313 if ($messageSeverity->isGreaterThan($this->highestSeverity)) {
314 $this->highestSeverity = $messageSeverity;
315 }
316
317 $this->systemMessages[] = array(
318 'module' => $module,
319 'count' => (int)$count,
320 'status' => $messageSeverity,
321 'text' => $text
322 );
323 }
324
325 /**
326 * Add a system information.
327 * This is a callback method for signal receivers.
328 *
329 * @param string $title The title of this system information
330 * @param string $value The associated value
331 * @param string $icon The icon html
332 */
333 public function addSystemInformation($title, $value, $icon)
334 {
335 $this->systemInformation[] = array(
336 'title' => $title,
337 'value' => $value,
338 'icon' => $icon
339 );
340 }
341
342 /**
343 * Checks whether the user has access to this toolbar item
344 *
345 * @return bool TRUE if user has access, FALSE if not
346 */
347 public function checkAccess()
348 {
349 return $this->getBackendUserAuthentication()->isAdmin();
350 }
351
352 /**
353 * Render system information dropdown
354 *
355 * @return string Icon HTML
356 */
357 public function getItem()
358 {
359 $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo'));
360 $icon = $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render('inline');
361 return '<span title="' . $title . '">' . $icon . '<span id="t3js-systeminformation-counter" class="badge"></span></span>';
362 }
363
364 /**
365 * Render drop down
366 *
367 * @return string Drop down HTML
368 */
369 public function getDropDown()
370 {
371 if (!$this->checkAccess()) {
372 return '';
373 }
374
375 $request = $this->standaloneView->getRequest();
376 $request->setControllerExtensionName('backend');
377 $this->standaloneView->assignMultiple(array(
378 'installToolUrl' => BackendUtility::getModuleUrl('system_InstallInstall'),
379 'messages' => $this->systemMessages,
380 'count' => $this->totalCount > $this->maximumCountInBadge ? $this->maximumCountInBadge . '+' : $this->totalCount,
381 'severityBadgeClass' => $this->severityBadgeClass,
382 'systemInformation' => $this->systemInformation
383 ));
384 return $this->standaloneView->render();
385 }
386
387 /**
388 * No additional attributes needed.
389 *
390 * @return array
391 */
392 public function getAdditionalAttributes()
393 {
394 return array();
395 }
396
397 /**
398 * This item has a drop down
399 *
400 * @return bool
401 */
402 public function hasDropDown()
403 {
404 return true;
405 }
406
407 /**
408 * Position relative to others
409 *
410 * @return int
411 */
412 public function getIndex()
413 {
414 return 75;
415 }
416
417 /**
418 * Returns the current BE user.
419 *
420 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
421 */
422 protected function getBackendUserAuthentication()
423 {
424 return $GLOBALS['BE_USER'];
425 }
426
427 /**
428 * Returns DatabaseConnection
429 *
430 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
431 */
432 protected function getDatabaseConnection()
433 {
434 return $GLOBALS['TYPO3_DB'];
435 }
436
437 /**
438 * Returns current PageRenderer
439 *
440 * @return PageRenderer
441 */
442 protected function getPageRenderer()
443 {
444 return GeneralUtility::makeInstance(PageRenderer::class);
445 }
446
447 /**
448 * Returns LanguageService
449 *
450 * @return \TYPO3\CMS\Lang\LanguageService
451 */
452 protected function getLanguageService()
453 {
454 return $GLOBALS['LANG'];
455 }
456
457 /**
458 * Get the SignalSlot dispatcher
459 *
460 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
461 */
462 protected function getSignalSlotDispatcher()
463 {
464 if (!isset($this->signalSlotDispatcher)) {
465 $this->signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
466 ->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
467 }
468 return $this->signalSlotDispatcher;
469 }
470 }