5d3f5a8016d52648deb18415d43bcf7387eaed8a
[Packages/TYPO3.CMS.git] / typo3 / sysext / filelist / Classes / Controller / FileListController.php
1 <?php
2 namespace TYPO3\CMS\Filelist\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 TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Script Class for creating the list of files in the File > Filelist module
22 *
23 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
24 */
25 class FileListController {
26
27 /**
28 * Module configuration
29 *
30 * @var array
31 */
32 public $MCONF = array();
33
34 /**
35 * @var array
36 */
37 public $MOD_MENU = array();
38
39 /**
40 * @var array
41 */
42 public $MOD_SETTINGS = array();
43
44 /**
45 * Accumulated HTML output
46 *
47 * @var string
48 */
49 public $content;
50
51 /**
52 * Document template object
53 *
54 * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
55 */
56 public $doc;
57
58 /**
59 * "id" -> the path to list.
60 *
61 * @var string
62 */
63 public $id;
64
65 /**
66 * @var \TYPO3\CMS\Core\Resource\Folder
67 */
68 protected $folderObject;
69
70 /**
71 * @var \TYPO3\CMS\Core\Messaging\FlashMessage
72 */
73 protected $errorMessage;
74
75 /**
76 * Pointer to listing
77 *
78 * @var int
79 */
80 public $pointer;
81
82 /**
83 * "Table"
84 *
85 * @var string
86 */
87 public $table;
88
89 /**
90 * Thumbnail mode.
91 *
92 * @var string
93 */
94 public $imagemode;
95
96 /**
97 * @var string
98 */
99 public $cmd;
100
101 /**
102 * @var bool
103 */
104 public $overwriteExistingFiles;
105
106 /**
107 * The file list object
108 *
109 * @var \TYPO3\CMS\Filelist\FileList
110 */
111 public $filelist = NULL;
112
113 /**
114 * Constructor
115 */
116 public function __construct() {
117 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_mod_file_list.xlf');
118 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xlf');
119 $GLOBALS['BE_USER']->modAccess($GLOBALS['MCONF'], TRUE);
120 }
121
122 /**
123 * Initialize variables, file object
124 * Incoming GET vars include id, pointer, table, imagemode
125 *
126 * @return void
127 */
128 public function init() {
129 // Setting GPvars:
130 $this->id = ($combinedIdentifier = GeneralUtility::_GP('id'));
131 $this->pointer = GeneralUtility::_GP('pointer');
132 $this->table = GeneralUtility::_GP('table');
133 $this->imagemode = GeneralUtility::_GP('imagemode');
134 $this->cmd = GeneralUtility::_GP('cmd');
135 $this->overwriteExistingFiles = GeneralUtility::_GP('overwriteExistingFiles');
136 // Setting module name:
137 $this->MCONF = $GLOBALS['MCONF'];
138 try {
139 if ($combinedIdentifier) {
140 /** @var $fileFactory \TYPO3\CMS\Core\Resource\ResourceFactory */
141 $fileFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class);
142 $storage = $fileFactory->getStorageObjectFromCombinedIdentifier($combinedIdentifier);
143 $identifier = substr($combinedIdentifier, strpos($combinedIdentifier, ':') + 1);
144 if (!$storage->hasFolder($identifier)) {
145 $identifier = $storage->getFolderIdentifierFromFileIdentifier($identifier);
146 }
147
148 $this->folderObject = $fileFactory->getFolderObjectFromCombinedIdentifier($storage->getUid() . ':' . $identifier);
149 // Disallow the rendering of the processing folder (e.g. could be called manually)
150 // and all folders without any defined storage
151 if ($this->folderObject && ($this->folderObject->getStorage()->getUid() == 0 || trim($this->folderObject->getStorage()->getProcessingFolder()->getIdentifier(), '/') === trim($this->folderObject->getIdentifier(), '/'))) {
152 $storage = $fileFactory->getStorageObjectFromCombinedIdentifier($combinedIdentifier);
153 $this->folderObject = $storage->getRootLevelFolder();
154 }
155 } else {
156 // Take the first object of the first storage
157 $fileStorages = $GLOBALS['BE_USER']->getFileStorages();
158 $fileStorage = reset($fileStorages);
159 if ($fileStorage) {
160 // Validating the input "id" (the path, directory!) and
161 // checking it against the mounts of the user. - now done in the controller
162 $this->folderObject = $fileStorage->getRootLevelFolder();
163 } else {
164 throw new \RuntimeException('Could not find any folder to be displayed.', 1349276894);
165 }
166 }
167 } catch (\TYPO3\CMS\Core\Resource\Exception $fileException) {
168 // Take the first object of the first storage
169 $fileStorages = $GLOBALS['BE_USER']->getFileStorages();
170 $fileStorage = reset($fileStorages);
171 if ($fileStorage) {
172 // Set folder object to null and throw a message later on
173 $this->folderObject = $fileStorage->getRootLevelFolder();
174 } else {
175 $this->folderObject = NULL;
176 }
177 $this->errorMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class,
178 sprintf($GLOBALS['LANG']->getLL('folderNotFoundMessage', TRUE),
179 htmlspecialchars($this->id)
180 ),
181 $GLOBALS['LANG']->getLL('folderNotFoundTitle', TRUE),
182 \TYPO3\CMS\Core\Messaging\FlashMessage::NOTICE
183 );
184 }
185 // Configure the "menu" - which is used internally to save the values of sorting, displayThumbs etc.
186 $this->menuConfig();
187 }
188
189 /**
190 * Setting the menu/session variables
191 *
192 * @return void
193 */
194 public function menuConfig() {
195 // MENU-ITEMS:
196 // If array, then it's a selector box menu
197 // If empty string it's just a variable, that will be saved.
198 // Values NOT in this array will not be saved in the settings-array for the module.
199 $this->MOD_MENU = array(
200 'sort' => '',
201 'reverse' => '',
202 'displayThumbs' => '',
203 'clipBoard' => '',
204 'bigControlPanel' => ''
205 );
206 // CLEANSE SETTINGS
207 $this->MOD_SETTINGS = BackendUtility::getModuleData(
208 $this->MOD_MENU,
209 GeneralUtility::_GP('SET'),
210 $this->MCONF['name']
211 );
212 }
213
214 /**
215 * Main function, creating the listing
216 *
217 * @return void
218 */
219 public function main() {
220 // Initialize the template object
221 $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
222 $this->doc->backPath = $GLOBALS['BACK_PATH'];
223 $this->doc->setModuleTemplate('EXT:filelist/Resources/Private/Templates/file_list.html');
224
225 /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
226 $pageRenderer = $this->doc->getPageRenderer();
227 $pageRenderer->loadPrototype();
228 $pageRenderer->loadJQuery();
229 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation');
230
231 // There there was access to this file path, continue, make the list
232 if ($this->folderObject) {
233
234 // Create filelisting object
235 $this->filelist = GeneralUtility::makeInstance(\TYPO3\CMS\Filelist\FileList::class);
236 $this->filelist->backPath = $GLOBALS['BACK_PATH'];
237 // Apply predefined values for hidden checkboxes
238 // Set predefined value for DisplayBigControlPanel:
239 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'activated') {
240 $this->MOD_SETTINGS['bigControlPanel'] = TRUE;
241 } elseif ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'deactivated') {
242 $this->MOD_SETTINGS['bigControlPanel'] = FALSE;
243 }
244 // Set predefined value for DisplayThumbnails:
245 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'activated') {
246 $this->MOD_SETTINGS['displayThumbs'] = TRUE;
247 } elseif ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'deactivated') {
248 $this->MOD_SETTINGS['displayThumbs'] = FALSE;
249 }
250 // Set predefined value for Clipboard:
251 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableClipBoard') === 'activated') {
252 $this->MOD_SETTINGS['clipBoard'] = TRUE;
253 } elseif ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableClipBoard') === 'deactivated') {
254 $this->MOD_SETTINGS['clipBoard'] = FALSE;
255 }
256 // If user never opened the list module, set the value for displayThumbs
257 if (!isset($this->MOD_SETTINGS['displayThumbs'])) {
258 $this->MOD_SETTINGS['displayThumbs'] = $GLOBALS['BE_USER']->uc['thumbnailsByDefault'];
259 }
260 $this->filelist->thumbs = $this->MOD_SETTINGS['displayThumbs'];
261 // Create clipboard object and initialize that
262 $this->filelist->clipObj = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Clipboard\Clipboard::class);
263 $this->filelist->clipObj->fileMode = 1;
264 $this->filelist->clipObj->initializeClipboard();
265 $CB = GeneralUtility::_GET('CB');
266 if ($this->cmd == 'setCB') {
267 $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(GeneralUtility::_POST('CBH'), GeneralUtility::_POST('CBC')), '_FILE');
268 }
269 if (!$this->MOD_SETTINGS['clipBoard']) {
270 $CB['setP'] = 'normal';
271 }
272 $this->filelist->clipObj->setCmd($CB);
273 $this->filelist->clipObj->cleanCurrent();
274 // Saves
275 $this->filelist->clipObj->endClipboard();
276 // If the "cmd" was to delete files from the list (clipboard thing), do that:
277 if ($this->cmd == 'delete') {
278 $items = $this->filelist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), '_FILE', 1);
279 if (count($items)) {
280 // Make command array:
281 $FILE = array();
282 foreach ($items as $v) {
283 $FILE['delete'][] = array('data' => $v);
284 }
285 // Init file processing object for deleting and pass the cmd array.
286 $fileProcessor = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\File\ExtendedFileUtility::class);
287 $fileProcessor->init(array(), $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
288 $fileProcessor->setActionPermissions();
289 $fileProcessor->dontCheckForUnique = $this->overwriteExistingFiles ? 1 : 0;
290 $fileProcessor->start($FILE);
291 $fileProcessor->processData();
292 $fileProcessor->pushErrorMessagesToFlashMessageQueue();
293 }
294 }
295 if (!isset($this->MOD_SETTINGS['sort'])) {
296 // Set default sorting
297 $this->MOD_SETTINGS['sort'] = 'file';
298 $this->MOD_SETTINGS['reverse'] = 0;
299 }
300 // Start up filelisting object, include settings.
301 $this->pointer = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
302 $this->filelist->start($this->folderObject, $this->pointer, $this->MOD_SETTINGS['sort'], $this->MOD_SETTINGS['reverse'], $this->MOD_SETTINGS['clipBoard'], $this->MOD_SETTINGS['bigControlPanel']);
303 // Generate the list
304 $this->filelist->generateList();
305 // Set top JavaScript:
306 $this->doc->JScode = $this->doc->wrapScriptTags('if (top.fsMod) top.fsMod.recentIds["file"] = "' . rawurlencode($this->id) . '";' . $this->filelist->CBfunctions());
307 // This will return content necessary for the context sensitive clickmenus to work: bodytag events, JavaScript functions and DIV-layers.
308 $this->doc->getContextMenuCode();
309 // Setting up the buttons and markers for docheader
310 list($buttons, $otherMarkers) = $this->filelist->getButtonsAndOtherMarkers($this->folderObject);
311 // add the folder info to the marker array
312 $otherMarkers['FOLDER_INFO'] = $this->filelist->getFolderInfo();
313 $docHeaderButtons = array_merge($this->getButtons(), $buttons);
314
315 // Include DragUploader only if we have write access
316 if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
317 && $this->folderObject->checkActionPermission('write')
318 ) {
319 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DragUploader');
320 $pageRenderer->addInlineLanguagelabelFile(
321 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('lang') . 'locallang_core.xlf',
322 'file_upload'
323 );
324 }
325
326 // Build the <body> for the module
327 $moduleHeadline = $this->getModuleHeadline();
328 // Create output
329 $pageContent = $moduleHeadline !== '' ? '<h1>' . $moduleHeadline . '</h1>' : '';
330
331 $pageContent .= '<form action="' . htmlspecialchars($this->filelist->listURL()) . '" method="post" name="dblistForm">';
332 $pageContent .= $this->filelist->HTMLcode;
333 $pageContent .= '<input type="hidden" name="cmd" /></form>';
334
335 // Making listing options:
336 if ($this->filelist->HTMLcode) {
337 $pageContent .= '
338
339 <!--
340 Listing options for extended view, clipboard and thumbnails
341 -->
342 <div id="typo3-listOptions">
343 ';
344 // Add "display bigControlPanel" checkbox:
345 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'selectable') {
346 $pageContent .= '<div class="checkbox">' .
347 '<label for="bigControlPanel">' .
348 BackendUtility::getFuncCheck($this->id, 'SET[bigControlPanel]', $this->MOD_SETTINGS['bigControlPanel'], '', '', 'id="bigControlPanel"') .
349 $GLOBALS['LANG']->getLL('bigControlPanel', TRUE) .
350 '</label>' .
351 '</div>';
352 }
353 // Add "display thumbnails" checkbox:
354 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'selectable') {
355 $pageContent .= '<div class="checkbox">' .
356 '<label for="checkDisplayThumbs">' .
357 BackendUtility::getFuncCheck($this->id, 'SET[displayThumbs]', $this->MOD_SETTINGS['displayThumbs'], '', '', 'id="checkDisplayThumbs"') .
358 $GLOBALS['LANG']->getLL('displayThumbs', TRUE) .
359 '</label>' .
360 '</div>';
361 }
362 // Add "clipboard" checkbox:
363 if ($GLOBALS['BE_USER']->getTSConfigVal('options.file_list.enableClipBoard') === 'selectable') {
364 $pageContent .= '<div class="checkbox">' .
365 '<label for="checkClipBoard">' .
366 BackendUtility::getFuncCheck($this->id, 'SET[clipBoard]', $this->MOD_SETTINGS['clipBoard'], '', '', 'id="checkClipBoard"') .
367 $GLOBALS['LANG']->getLL('clipBoard', TRUE) .
368 '</label>' .
369 '</div>';
370 }
371 $pageContent .= '
372 </div>
373 ';
374 // Set clipboard:
375 if ($this->MOD_SETTINGS['clipBoard']) {
376 $pageContent .= $this->filelist->clipObj->printClipboard();
377 $pageContent .= BackendUtility::cshItem('xMOD_csh_corebe', 'filelist_clipboard', $GLOBALS['BACK_PATH']);
378 }
379 }
380 $markerArray = array(
381 'CSH' => $docHeaderButtons['csh'],
382 'FUNC_MENU' => BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']),
383 'CONTENT' => ($this->errorMessage ? $this->errorMessage->render() : '') . $pageContent,
384 'FOLDER_IDENTIFIER' => $this->folderObject->getCombinedIdentifier(),
385 'FILEDENYPATERN' => $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'],
386 'MAXFILESIZE' => GeneralUtility::getMaxUploadFileSize() * 1024,
387 );
388 $this->content = $this->doc->moduleBody(array(), $docHeaderButtons, array_merge($markerArray, $otherMarkers));
389 // Renders the module page
390 $this->content = $this->doc->render($GLOBALS['LANG']->getLL('files'), $this->content);
391 } else {
392 $content = '';
393 if ($this->errorMessage) {
394 $this->errorMessage->setSeverity(\TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
395 $content = $this->doc->moduleBody(array(), array_merge(array('REFRESH' => '', 'PASTE' => '', 'LEVEL_UP' => ''), $this->getButtons()), array('CSH' => '', 'TITLE' => '', 'FOLDER_INFO' => '', 'PAGE_ICON' => '', 'FUNC_MENU' => '', 'CONTENT' => $this->errorMessage->render()));
396 }
397 // Create output - no access (no warning though)
398 $this->content = $this->doc->render($GLOBALS['LANG']->getLL('files'), $content);
399 }
400 }
401
402 /**
403 * Get main headline based on active folder or storage for backend module
404 *
405 * Folder names are resolved to their special names like done in the tree view.
406 *
407 * @return string
408 */
409 protected function getModuleHeadline() {
410 $name = $this->folderObject->getName();
411 if ($name === '') {
412 // Show storage name on storage root
413 if ($this->folderObject->getIdentifier() === '/') {
414 $name = $this->folderObject->getStorage()->getName();
415 }
416 } else {
417 $name = key(\TYPO3\CMS\Core\Resource\Utility\ListUtility::resolveSpecialFolderNames(
418 array($name => $this->folderObject)
419 ));
420 }
421 return $name;
422 }
423
424 /**
425 * Outputting the accumulated content to screen
426 *
427 * @return void
428 */
429 public function printContent() {
430 echo $this->content;
431 }
432
433 /**
434 * Create the panel of buttons for submitting the form or otherwise perform operations.
435 *
436 * @return array All available buttons as an assoc. array
437 */
438 public function getButtons() {
439 $buttons = array(
440 'csh' => '',
441 'shortcut' => '',
442 'upload' => '',
443 'new' => ''
444 );
445 // Add shortcut
446 if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
447 $buttons['shortcut'] = $this->doc->makeShortcutIcon('pointer,id,target,table', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
448 }
449 // FileList Module CSH:
450 $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'filelist_module', $GLOBALS['BACK_PATH'], '', TRUE);
451 // Upload button (only if upload to this directory is allowed)
452 if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File') && $this->folderObject->checkActionPermission('write')) {
453 $buttons['upload'] = '<a href="' . htmlspecialchars($GLOBALS['BACK_PATH']
454 . BackendUtility::getModuleUrl(
455 'file_upload',
456 array(
457 'target' => $this->folderObject->getCombinedIdentifier(),
458 'returnUrl' => $this->filelist->listURL(),
459 )
460 )) . '" id="button-upload" title="' . $GLOBALS['LANG']->makeEntities($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.upload', TRUE)) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-upload') . '</a>';
461 }
462 // New folder button
463 if ($this->folderObject && $this->folderObject->checkActionPermission('write')
464 && ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File') || $this->folderObject->checkActionPermission('add'))
465 ) {
466 $buttons['new'] = '<a href="' . htmlspecialchars($GLOBALS['BACK_PATH']
467 . BackendUtility::getModuleUrl(
468 'file_newfolder',
469 array(
470 'target' => $this->folderObject->getCombinedIdentifier(),
471 'returnUrl' => $this->filelist->listURL(),
472 )
473 )) . '" title="' . $GLOBALS['LANG']->makeEntities($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.new', TRUE)) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new') . '</a>';
474 }
475 return $buttons;
476 }
477
478 }