TYPO3  7.6
FileListController.php
Go to the documentation of this file.
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 
39 
44 {
45 
52  public $MCONF = array();
53 
57  public $MOD_MENU = array();
58 
62  public $MOD_SETTINGS = array();
63 
69  public $doc;
70 
76  public $id;
77 
81  protected $folderObject;
82 
86  protected $errorMessage;
87 
93  public $pointer;
94 
99  public $table;
100 
106  public $imagemode;
107 
111  public $cmd;
112 
120 
126  public $filelist = null;
127 
133  protected $moduleName = 'file_list';
134 
138  protected $fileRepository;
139 
143  protected $view;
144 
150  protected $defaultViewObjectName = BackendTemplateView::class;
151 
155  public function injectFileRepository(\TYPO3\CMS\Core\Resource\FileRepository $fileRepository)
156  {
157  $this->fileRepository = $fileRepository;
158  }
159 
168  public function initializeObject()
169  {
170  $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
171  $this->getLanguageService()->includeLLFile('EXT:lang/locallang_mod_file_list.xlf');
172  $this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
173 
174  // Setting GPvars:
175  $this->id = ($combinedIdentifier = GeneralUtility::_GP('id'));
176  $this->pointer = GeneralUtility::_GP('pointer');
177  $this->table = GeneralUtility::_GP('table');
178  $this->imagemode = GeneralUtility::_GP('imagemode');
179  $this->cmd = GeneralUtility::_GP('cmd');
180  $this->overwriteExistingFiles = DuplicationBehavior::cast(GeneralUtility::_GP('overwriteExistingFiles'));
181 
182  try {
183  if ($combinedIdentifier) {
185  $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
186  $storage = $resourceFactory->getStorageObjectFromCombinedIdentifier($combinedIdentifier);
187  $identifier = substr($combinedIdentifier, strpos($combinedIdentifier, ':') + 1);
188  if (!$storage->hasFolder($identifier)) {
189  $identifier = $storage->getFolderIdentifierFromFileIdentifier($identifier);
190  }
191 
192  $this->folderObject = $resourceFactory->getFolderObjectFromCombinedIdentifier($storage->getUid() . ':' . $identifier);
193  // Disallow access to fallback storage 0
194  if ($storage->getUid() === 0) {
195  throw new Exception\InsufficientFolderAccessPermissionsException('You are not allowed to access files outside your storages',
196  1434539815);
197  }
198  // Disallow the rendering of the processing folder (e.g. could be called manually)
199  if ($this->folderObject && $storage->isProcessingFolder($this->folderObject)) {
200  $this->folderObject = $storage->getRootLevelFolder();
201  }
202  } else {
203  // Take the first object of the first storage
204  $fileStorages = $this->getBackendUser()->getFileStorages();
205  $fileStorage = reset($fileStorages);
206  if ($fileStorage) {
207  $this->folderObject = $fileStorage->getRootLevelFolder();
208  } else {
209  throw new \RuntimeException('Could not find any folder to be displayed.', 1349276894);
210  }
211  }
212 
213  if ($this->folderObject && !$this->folderObject->getStorage()->isWithinFileMountBoundaries($this->folderObject)) {
214  throw new \RuntimeException('Folder not accessible.', 1430409089);
215  }
216  } catch (Exception\InsufficientFolderAccessPermissionsException $permissionException) {
217  $this->folderObject = null;
218  $this->errorMessage = GeneralUtility::makeInstance(FlashMessage::class,
219  sprintf(
220  $this->getLanguageService()->getLL('missingFolderPermissionsMessage', true),
221  htmlspecialchars($this->id)
222  ),
223  $this->getLanguageService()->getLL('missingFolderPermissionsTitle', true),
225  );
226  } catch (Exception $fileException) {
227  // Set folder object to null and throw a message later on
228  $this->folderObject = null;
229  // Take the first object of the first storage
230  $fileStorages = $this->getBackendUser()->getFileStorages();
231  $fileStorage = reset($fileStorages);
232  if ($fileStorage instanceof \TYPO3\CMS\Core\Resource\ResourceStorage) {
233  $this->folderObject = $fileStorage->getRootLevelFolder();
234  if (!$fileStorage->isWithinFileMountBoundaries($this->folderObject)) {
235  $this->folderObject = null;
236  }
237  }
238  $this->errorMessage = GeneralUtility::makeInstance(FlashMessage::class,
239  sprintf(
240  $this->getLanguageService()->getLL('folderNotFoundMessage', true),
241  htmlspecialchars($this->id)
242  ),
243  $this->getLanguageService()->getLL('folderNotFoundTitle', true),
245  );
246  } catch (\RuntimeException $e) {
247  $this->folderObject = null;
248  $this->errorMessage = GeneralUtility::makeInstance(FlashMessage::class,
249  $e->getMessage() . ' (' . $e->getCode() . ')',
250  $this->getLanguageService()->getLL('folderNotFoundTitle', true),
252  );
253  }
254 
255  if ($this->folderObject && !$this->folderObject->getStorage()->checkFolderActionPermission('read',
256  $this->folderObject)
257  ) {
258  $this->folderObject = null;
259  }
260 
261  // Configure the "menu" - which is used internally to save the values of sorting, displayThumbs etc.
262  $this->menuConfig();
263  }
264 
270  public function menuConfig()
271  {
272  // MENU-ITEMS:
273  // If array, then it's a selector box menu
274  // If empty string it's just a variable, that will be saved.
275  // Values NOT in this array will not be saved in the settings-array for the module.
276  $this->MOD_MENU = array(
277  'sort' => '',
278  'reverse' => '',
279  'displayThumbs' => '',
280  'clipBoard' => '',
281  'bigControlPanel' => ''
282  );
283  // CLEANSE SETTINGS
284  $this->MOD_SETTINGS = BackendUtility::getModuleData(
285  $this->MOD_MENU,
286  GeneralUtility::_GP('SET'),
287  $this->moduleName
288  );
289  }
290 
297  public function initializeView(ViewInterface $view)
298  {
300  parent::initializeView($view);
301  $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
302  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation');
303  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileSearch');
304  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
305  $this->registerDocHeaderButtons();
306  }
307 
311  public function initializeIndexAction()
312  {
313  // Apply predefined values for hidden checkboxes
314  // Set predefined value for DisplayBigControlPanel:
315  $backendUser = $this->getBackendUser();
316  if ($backendUser->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'activated') {
317  $this->MOD_SETTINGS['bigControlPanel'] = true;
318  } elseif ($backendUser->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'deactivated') {
319  $this->MOD_SETTINGS['bigControlPanel'] = false;
320  }
321  // Set predefined value for DisplayThumbnails:
322  if ($backendUser->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'activated') {
323  $this->MOD_SETTINGS['displayThumbs'] = true;
324  } elseif ($backendUser->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'deactivated') {
325  $this->MOD_SETTINGS['displayThumbs'] = false;
326  }
327  // Set predefined value for Clipboard:
328  if ($backendUser->getTSConfigVal('options.file_list.enableClipBoard') === 'activated') {
329  $this->MOD_SETTINGS['clipBoard'] = true;
330  } elseif ($backendUser->getTSConfigVal('options.file_list.enableClipBoard') === 'deactivated') {
331  $this->MOD_SETTINGS['clipBoard'] = false;
332  }
333  // If user never opened the list module, set the value for displayThumbs
334  if (!isset($this->MOD_SETTINGS['displayThumbs'])) {
335  $this->MOD_SETTINGS['displayThumbs'] = $backendUser->uc['thumbnailsByDefault'];
336  }
337  if (!isset($this->MOD_SETTINGS['sort'])) {
338  // Set default sorting
339  $this->MOD_SETTINGS['sort'] = 'file';
340  $this->MOD_SETTINGS['reverse'] = 0;
341  }
342  }
343 
347  public function indexAction()
348  {
349  $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
350  $pageRenderer->setTitle($this->getLanguageService()->getLL('files'));
351 
352  // There there was access to this file path, continue, make the list
353  if ($this->folderObject) {
354  // Create fileListing object
355  $this->filelist = GeneralUtility::makeInstance(FileList::class, $this);
356  $this->filelist->thumbs = $this->MOD_SETTINGS['displayThumbs'];
357  // Create clipboard object and initialize that
358  $this->filelist->clipObj = GeneralUtility::makeInstance(Clipboard::class);
359  $this->filelist->clipObj->fileMode = 1;
360  $this->filelist->clipObj->initializeClipboard();
361  $CB = GeneralUtility::_GET('CB');
362  if ($this->cmd == 'setCB') {
363  $CB['el'] = $this->filelist->clipObj->cleanUpCBC(array_merge(GeneralUtility::_POST('CBH'),
364  (array)GeneralUtility::_POST('CBC')), '_FILE');
365  }
366  if (!$this->MOD_SETTINGS['clipBoard']) {
367  $CB['setP'] = 'normal';
368  }
369  $this->filelist->clipObj->setCmd($CB);
370  $this->filelist->clipObj->cleanCurrent();
371  // Saves
372  $this->filelist->clipObj->endClipboard();
373  // If the "cmd" was to delete files from the list (clipboard thing), do that:
374  if ($this->cmd == 'delete') {
375  $items = $this->filelist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), '_FILE', 1);
376  if (!empty($items)) {
377  // Make command array:
378  $FILE = array();
379  foreach ($items as $v) {
380  $FILE['delete'][] = array('data' => $v);
381  }
382  // Init file processing object for deleting and pass the cmd array.
384  $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
385  $fileProcessor->init(array(), $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
386  $fileProcessor->setActionPermissions();
387  $fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
388  $fileProcessor->start($FILE);
389  $fileProcessor->processData();
390  $fileProcessor->pushErrorMessagesToFlashMessageQueue();
391  }
392  }
393  // Start up filelisting object, include settings.
394  $this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
395  $this->filelist->start($this->folderObject, $this->pointer, $this->MOD_SETTINGS['sort'],
396  $this->MOD_SETTINGS['reverse'], $this->MOD_SETTINGS['clipBoard'],
397  $this->MOD_SETTINGS['bigControlPanel']);
398  // Generate the list
399  $this->filelist->generateList();
400  // Set top JavaScript:
401  $this->view->getModuleTemplate()->addJavaScriptCode(
402  'FileListIndex',
403  'if (top.fsMod) top.fsMod.recentIds["file"] = "' . rawurlencode($this->id) . '";' . $this->filelist->CBfunctions() . '
404  function jumpToUrl(URL) {
405  window.location.href = URL;
406  return false;
407  }
408  ');
409 
410  // Include DragUploader only if we have write access
411  if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')
412  && $this->folderObject->checkActionPermission('write')
413  ) {
414  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DragUploader');
415  $pageRenderer->addInlineLanguageLabelFile(
416  ExtensionManagementUtility::extPath('lang') . 'locallang_core.xlf',
417  'file_upload'
418  );
419  }
420 
421  // Setting up the buttons
422  $this->registerButtons();
423 
424  $pageRecord = [
425  '_additional_info' => $this->filelist->getFolderInfo(),
426  'combined_identifier' => $this->folderObject->getCombinedIdentifier(),
427  ];
428  $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
429 
430  $this->view->assign('headline', $this->getModuleHeadline());
431  $this->view->assign('listHtml', $this->filelist->HTMLcode);
432  $this->view->assign('checkboxes', [
433  'bigControlPanel' => [
434  'enabled' => $this->getBackendUser()->getTSConfigVal('options.file_list.enableDisplayBigControlPanel') === 'selectable',
435  'label' => $this->getLanguageService()->getLL('bigControlPanel', true),
436  'html' => BackendUtility::getFuncCheck($this->id, 'SET[bigControlPanel]',
437  $this->MOD_SETTINGS['bigControlPanel'], '', '', 'id="bigControlPanel"'),
438  ],
439  'displayThumbs' => [
440  'enabled' => $this->getBackendUser()->getTSConfigVal('options.file_list.enableDisplayThumbnails') === 'selectable',
441  'label' => $this->getLanguageService()->getLL('displayThumbs', true),
442  'html' => BackendUtility::getFuncCheck($this->id, 'SET[displayThumbs]',
443  $this->MOD_SETTINGS['displayThumbs'], '', '', 'id="checkDisplayThumbs"'),
444  ],
445  'enableClipBoard' => [
446  'enabled' => $this->getBackendUser()->getTSConfigVal('options.file_list.enableClipBoard') === 'selectable',
447  'label' => $this->getLanguageService()->getLL('clipBoard', true),
448  'html' => BackendUtility::getFuncCheck($this->id, 'SET[clipBoard]',
449  $this->MOD_SETTINGS['clipBoard'], '', '', 'id="checkClipBoard"'),
450  ]
451  ]);
452  $this->view->assign('showClipBoard', (bool)$this->MOD_SETTINGS['clipBoard']);
453  $this->view->assign('clipBoardHtml', $this->filelist->clipObj->printClipboard());
454  $this->view->assign('folderIdentifier', $this->folderObject->getCombinedIdentifier());
455  $this->view->assign('fileDenyPattern', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern']);
456  $this->view->assign('maxFileSize', GeneralUtility::getMaxUploadFileSize() * 1024);
457  } else {
458  $this->forward('missingFolder');
459  }
460  }
461 
465  public function missingFolderAction()
466  {
467  if ($this->errorMessage) {
468  $this->errorMessage->setSeverity(FlashMessage::ERROR);
469  $this->controllerContext->getFlashMessageQueue('core.template.flashMessages')->addMessage($this->errorMessage);
470  }
471  }
472 
478  public function searchAction($searchWord = '')
479  {
480  if (empty($searchWord)) {
481  $this->forward('index');
482  }
483 
484  $fileFacades = [];
485  $files = $this->fileRepository->searchByName($this->folderObject, $searchWord);
486 
487  if (empty($files)) {
488  $this->controllerContext->getFlashMessageQueue('core.template.flashMessages')->addMessage(
489  new FlashMessage(LocalizationUtility::translate('flashmessage.no_results', 'filelist'), '',
491  );
492  } else {
493  foreach ($files as $file) {
494  $fileFacades[] = new \TYPO3\CMS\Filelist\FileFacade($file);
495  }
496  }
497 
498  $this->view->assign('searchWord', $searchWord);
499  $this->view->assign('files', $fileFacades);
500  $this->view->assign('settings', [
501  'jsConfirmationDelete' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE)
502  ]);
503  }
504 
511  protected function getModuleHeadline()
512  {
513  $name = $this->folderObject->getName();
514  if ($name === '') {
515  // Show storage name on storage root
516  if ($this->folderObject->getIdentifier() === '/') {
517  $name = $this->folderObject->getStorage()->getName();
518  }
519  } else {
520  $name = key(ListUtility::resolveSpecialFolderNames(
521  array($name => $this->folderObject)
522  ));
523  }
524  return $name;
525  }
526 
533  protected function registerDocHeaderButtons()
534  {
536  $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
537 
538  // CSH
539  $cshButton = $buttonBar->makeHelpButton()
540  ->setModuleName('xMOD_csh_corebe')
541  ->setFieldName('filelist_module');
542  $buttonBar->addButton($cshButton);
543  }
544 
550  protected function registerButtons()
551  {
553  $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
554 
556  $iconFactory = $this->view->getModuleTemplate()->getIconFactory();
557 
559  $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
560 
561  // Refresh page
562  $refreshButton = $buttonBar->makeLinkButton()
563  ->setHref(GeneralUtility::linkThisScript(array(
564  'target' => rawurlencode($this->folderObject->getCombinedIdentifier()),
565  'imagemode' => $this->filelist->thumbs
566  )))
567  ->setTitle($this->getLanguageService()->makeEntities($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.reload',
568  true)))
569  ->setIcon($iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL));
570  $buttonBar->addButton($refreshButton, ButtonBar::BUTTON_POSITION_RIGHT);
571 
572  // Level up
573  try {
574  $currentStorage = $this->folderObject->getStorage();
575  $parentFolder = $this->folderObject->getParentFolder();
576  if ($parentFolder->getIdentifier() !== $this->folderObject->getIdentifier() && $currentStorage->isWithinFileMountBoundaries($parentFolder)) {
577  $levelUpButton = $buttonBar->makeLinkButton()
578  ->setHref(BackendUtility::getModuleUrl('file_FilelistList',
579  ['id' => $parentFolder->getCombinedIdentifier()]))
580  ->setOnClick('top.document.getElementsByName("navigation")[0].contentWindow.Tree.highlightActiveItem("file","folder' . GeneralUtility::md5int($parentFolder->getCombinedIdentifier()) . '_"+top.fsMod.currentBank)')
581  ->setTitle($this->getLanguageService()->makeEntities($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.upOneLevel',
582  true)))
583  ->setIcon($iconFactory->getIcon('actions-view-go-up', Icon::SIZE_SMALL));
584  $buttonBar->addButton($levelUpButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
585  }
586  } catch (\Exception $e) {
587  }
588 
589  // Shortcut
590  if ($this->getBackendUser()->mayMakeShortcut()) {
591  $shortCutButton = $buttonBar->makeShortcutButton()->setModuleName('file_FilelistList');
592  $buttonBar->addButton($shortCutButton, ButtonBar::BUTTON_POSITION_RIGHT);
593  }
594 
595  // Upload button (only if upload to this directory is allowed)
596  if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission('add',
597  'File') && $this->folderObject->checkActionPermission('write')
598  ) {
599  $uploadButton = $buttonBar->makeLinkButton()
600  ->setHref(BackendUtility::getModuleUrl(
601  'file_upload',
602  array(
603  'target' => $this->folderObject->getCombinedIdentifier(),
604  'returnUrl' => $this->filelist->listURL(),
605  )
606  ))
607  ->setClasses('t3js-drag-uploader-trigger')
608  ->setTitle($this->getLanguageService()->makeEntities($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:cm.upload',
609  true)))
610  ->setIcon($iconFactory->getIcon('actions-edit-upload', Icon::SIZE_SMALL));
611  $buttonBar->addButton($uploadButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
612  }
613 
614  // New folder button
615  if ($this->folderObject && $this->folderObject->checkActionPermission('write')
616  && ($this->folderObject->getStorage()->checkUserActionPermission('add',
617  'File') || $this->folderObject->checkActionPermission('add'))
618  ) {
619  $newButton = $buttonBar->makeLinkButton()
620  ->setHref(BackendUtility::getModuleUrl(
621  'file_newfolder',
622  array(
623  'target' => $this->folderObject->getCombinedIdentifier(),
624  'returnUrl' => $this->filelist->listURL(),
625  )
626  ))
627  ->setTitle($this->getLanguageService()->makeEntities($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:cm.new',
628  true)))
629  ->setIcon($iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL));
630  $buttonBar->addButton($newButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
631  }
632 
633  // Add paste button if clipboard is initialized
634  if ($this->filelist->clipObj instanceof Clipboard && $this->folderObject->checkActionPermission('write')) {
635  $elFromTable = $this->filelist->clipObj->elFromTable('_FILE');
636  if (!empty($elFromTable)) {
637  $addPasteButton = true;
638  $elToConfirm = array();
639  foreach ($elFromTable as $key => $element) {
640  $clipBoardElement = $resourceFactory->retrieveFileOrFolderObject($element);
641  if ($clipBoardElement instanceof Folder && $clipBoardElement->getStorage()->isWithinFolder($clipBoardElement,
642  $this->folderObject)
643  ) {
644  $addPasteButton = false;
645  }
646  $elToConfirm[$key] = $clipBoardElement->getName();
647  }
648  if ($addPasteButton) {
649  $pasteButton = $buttonBar->makeLinkButton()
650  ->setHref($this->filelist->clipObj->pasteUrl('_FILE',
651  $this->folderObject->getCombinedIdentifier()))
652  ->setOnClick('return ' . htmlspecialchars($this->filelist->clipObj->confirmMsg('_FILE',
653  $this->folderObject->getReadablePath(), 'into', $elToConfirm)))
654  ->setTitle($this->getLanguageService()->getLL('clip_paste', true))
655  ->setIcon($iconFactory->getIcon('actions-document-paste-after', Icon::SIZE_SMALL));
656  $buttonBar->addButton($pasteButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
657  }
658  }
659  }
660  }
661 
667  protected function getLanguageService()
668  {
669  return $GLOBALS['LANG'];
670  }
671 
677  protected function getBackendUser()
678  {
679  return $GLOBALS['BE_USER'];
680  }
681 }