[TASK] Protect info extension
[Packages/TYPO3.CMS.git] / typo3 / sysext / info / Classes / Controller / PageInformationController.php
1 <?php
2 namespace TYPO3\CMS\Info\Controller;
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\ServerRequestInterface;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Backend\View\PageLayoutView;
20 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
21 use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
22 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
23 use TYPO3\CMS\Core\Localization\LanguageService;
24 use TYPO3\CMS\Core\Site\Entity\NullSite;
25 use TYPO3\CMS\Core\Site\Entity\PseudoSite;
26 use TYPO3\CMS\Core\Site\Entity\Site;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28
29 /**
30 * Class for displaying page information (records, page record properties) in Web -> Info
31 */
32 class PageInformationController
33 {
34 use PublicPropertyDeprecationTrait;
35 use PublicMethodDeprecationTrait;
36
37 /**
38 * @var array
39 */
40 private $deprecatedPublicProperties = [
41 'pObj' => 'Using PageInformationController::$pObj is deprecated and will not be possible anymore in TYPO3 v10.',
42 'function_key' => 'Using PageInformationController::$function_key is deprecated, property will be removed in TYPO3 v10.',
43 'extClassConf' => 'Using PageInformationController::$extClassConf is deprecated, property will be removed in TYPO3 v10.',
44 'localLangFile' => 'Using PageInformationController::$localLangFile is deprecated, property will be removed in TYPO3 v10.',
45 'extObj' => 'Using PageInformationController::$extObj is deprecated, property will be removed in TYPO3 v10.',
46 ];
47
48 /**
49 * @var array
50 */
51 private $deprecatedPublicMethods = [
52 'modMenu' => 'Using PageInformationController::modMenu() is deprecated and will not be possible anymore in TYPO3 v10.',
53 'extObjContent' => 'Using PageInformationController::extObjContent() is deprecated, method will be removed in TYPO3 v10.',
54 ];
55
56 /**
57 * @var array
58 */
59 protected $fieldConfiguration = [];
60
61 /**
62 * @var int Value of the GET/POST var 'id'
63 */
64 protected $id;
65
66 /**
67 * @var InfoModuleController Contains a reference to the parent calling object
68 */
69 protected $pObj;
70
71 /**
72 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
73 */
74 protected $extObj;
75
76 /**
77 * Can be hardcoded to the name of a locallang.xlf file (from the same directory as the class file) to use/load
78 * and is included / added to $GLOBALS['LOCAL_LANG']
79 *
80 * @var string
81 */
82 protected $localLangFile = '';
83
84 /**
85 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
86 */
87 protected $extClassConf;
88
89 /**
90 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
91 */
92 protected $function_key = '';
93
94 /**
95 * Init, called from parent object
96 *
97 * @param InfoModuleController $pObj A reference to the parent (calling) object
98 */
99 public function init($pObj)
100 {
101 $this->pObj = $pObj;
102 // Local lang:
103 if (!empty($this->localLangFile)) {
104 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
105 $this->getLanguageService()->includeLLFile($this->localLangFile);
106 }
107 $this->id = (int)GeneralUtility::_GP('id');
108 // Setting MOD_MENU items as we need them for logging:
109 $this->pObj->MOD_MENU = array_merge($this->pObj->MOD_MENU, $this->modMenu());
110 }
111
112 /**
113 * Main, called from parent object
114 *
115 * @return string Output HTML for the module.
116 */
117 public function main()
118 {
119 $languageService = $this->getLanguageService();
120 $theOutput = '<h1>' . htmlspecialchars($languageService->sL('LLL:EXT:info/Resources/Private/Language/locallang_webinfo.xlf:page_title')) . '</h1>';
121 $dblist = GeneralUtility::makeInstance(PageLayoutView::class);
122 $dblist->descrTable = '_MOD_web_info';
123 $dblist->thumbs = 0;
124 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
125 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
126 $dblist->script = (string)$uriBuilder->buildUriFromRoute('web_info');
127 $dblist->showIcon = 0;
128 $dblist->setLMargin = 0;
129 $dblist->agePrefixes = $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears');
130 $dblist->pI_showUser = true;
131
132 if (isset($this->fieldConfiguration[$this->pObj->MOD_SETTINGS['pages']])) {
133 $dblist->fieldArray = $this->fieldConfiguration[$this->pObj->MOD_SETTINGS['pages']]['fields'];
134 }
135
136 // PAGES:
137 $this->pObj->MOD_SETTINGS['pages_levels'] = $this->pObj->MOD_SETTINGS['depth'];
138 // ONLY for the sake of dblist module which uses this value.
139 $h_func = BackendUtility::getDropdownMenu($this->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
140 $h_func .= BackendUtility::getDropdownMenu($this->id, 'SET[pages]', $this->pObj->MOD_SETTINGS['pages'], $this->pObj->MOD_MENU['pages']);
141 $dblist->start($this->id, 'pages', 0);
142 $dblist->generateList();
143
144 $theOutput .= '<div class="form-inline form-inline-spaced">'
145 . $h_func
146 . '<div class="form-group">'
147 . BackendUtility::cshItem($dblist->descrTable, 'func_' . $this->pObj->MOD_SETTINGS['pages'], null, '<span class="btn btn-default btn-sm">|</span>')
148 . '</div>'
149 . '</div>'
150 . $dblist->HTMLcode;
151
152 // Additional footer content
153 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/web_info/class.tx_cms_webinfo.php']['drawFooterHook'] ?? [] as $hook) {
154 // @todo: request object should be submitted here as soon as it is available in v10.
155 $params = [];
156 $theOutput .= GeneralUtility::callUserFunction($hook, $params, $this);
157 }
158 return $theOutput;
159 }
160
161 /**
162 * Returns the menu array
163 *
164 * @return array
165 */
166 protected function modMenu()
167 {
168 $menu = [
169 'pages' => [],
170 'depth' => [
171 0 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
172 1 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
173 2 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
174 3 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
175 4 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
176 999 => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_infi')
177 ]
178 ];
179
180 // Using $GLOBALS['TYPO3_REQUEST'] since $request is not available at this point
181 // @todo: Refactor mess and have $request available
182 $this->fillFieldConfiguration($this->id, $GLOBALS['TYPO3_REQUEST']);
183 foreach ($this->fieldConfiguration as $key => $item) {
184 $menu['pages'][$key] = $item['label'];
185 }
186 return $menu;
187 }
188
189 /**
190 * Function, which returns all tables to
191 * which the user has access. Also a set of standard tables (pages, sys_filemounts, etc...)
192 * are filtered out. So what is left is basically all tables which makes sense to list content from.
193 *
194 * @return string
195 */
196 protected function cleanTableNames(): string
197 {
198 // Get all table names:
199 $tableNames = array_flip(array_keys($GLOBALS['TCA']));
200 // Unset common names:
201 unset($tableNames['pages']);
202 unset($tableNames['sys_filemounts']);
203 unset($tableNames['sys_action']);
204 unset($tableNames['sys_workflows']);
205 unset($tableNames['be_users']);
206 unset($tableNames['be_groups']);
207 $allowedTableNames = [];
208 // Traverse table names and set them in allowedTableNames array IF they can be read-accessed by the user.
209 if (is_array($tableNames)) {
210 foreach ($tableNames as $k => $v) {
211 if (!$GLOBALS['TCA'][$k]['ctrl']['hideTable'] && $this->getBackendUser()->check('tables_select', $k)) {
212 $allowedTableNames['table_' . $k] = $k;
213 }
214 }
215 }
216 return implode(',', array_keys($allowedTableNames));
217 }
218
219 /**
220 * Generate configuration for field selection
221 *
222 * @param int $pageId current page id
223 * @param ServerRequestInterface $request
224 */
225 protected function fillFieldConfiguration(int $pageId, ServerRequestInterface $request)
226 {
227 $modTSconfig = BackendUtility::getPagesTSconfig($pageId)['mod.']['web_info.']['fieldDefinitions.'] ?? [];
228 foreach ($modTSconfig as $key => $item) {
229 $fieldList = str_replace('###ALL_TABLES###', $this->cleanTableNames(), $item['fields']);
230 $fields = GeneralUtility::trimExplode(',', $fieldList, true);
231 if ((int)$key === 0) {
232 // If "Basic settings" is rendered, hide the alias field on trees that have a site configuration
233 // and hide the slug field on PseudoSites. On NullSites (pid 0), show both.
234 $site = $request->getAttribute('site');
235 if ($site instanceof PseudoSite) {
236 $fields = array_diff($fields, ['slug']);
237 } elseif ($site instanceof Site && !$site instanceof NullSite) {
238 $fields = array_diff($fields, ['alias']);
239 }
240 }
241 $key = trim($key, '.');
242 $this->fieldConfiguration[$key] = [
243 'label' => $item['label'] ? $GLOBALS['LANG']->sL($item['label']) : $key,
244 'fields' => $fields
245 ];
246 }
247 }
248
249 /**
250 * Called from InfoModuleController until deprecation removal in v10
251 *
252 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
253 */
254 public function checkExtObj()
255 {
256 if (is_array($this->extClassConf) && $this->extClassConf['name']) {
257 $this->extObj = GeneralUtility::makeInstance($this->extClassConf['name']);
258 $this->extObj->init($this->pObj, $this->extClassConf);
259 // Re-write:
260 $this->pObj->MOD_SETTINGS = BackendUtility::getModuleData($this->pObj->MOD_MENU, GeneralUtility::_GP('SET'), 'web_info');
261 }
262 }
263
264 /**
265 * Calls the main function inside ANOTHER sub-submodule which might exist.
266 *
267 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0.
268 */
269 protected function extObjContent()
270 {
271 if (is_object($this->extObj)) {
272 return $this->extObj->main();
273 }
274 }
275
276 /**
277 * @return BackendUserAuthentication
278 */
279 protected function getBackendUser(): BackendUserAuthentication
280 {
281 return $GLOBALS['BE_USER'];
282 }
283
284 /**
285 * @return LanguageService
286 */
287 protected function getLanguageService(): LanguageService
288 {
289 return $GLOBALS['LANG'];
290 }
291 }