TYPO3  7.6
FileBrowser.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Recordlist\Browser;
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 
31 
36 {
45  protected $expandFolder;
46 
50  protected $selectedFolder;
51 
57  protected $elements = array();
58 
62  protected $searchWord;
63 
67  protected $fileRepository;
68 
72  protected function initialize()
73  {
74  parent::initialize();
75  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/BrowseFiles');
76  $this->fileRepository = GeneralUtility::makeInstance(FileRepository::class);
77  }
78 
82  protected function initVariables()
83  {
84  parent::initVariables();
85  $this->expandFolder = GeneralUtility::_GP('expandFolder');
86  $this->searchWord = (string)GeneralUtility::_GP('searchWord');
87  }
88 
95  public function processSessionData($data)
96  {
97  if ($this->expandFolder !== null) {
98  $data['expandFolder'] = $this->expandFolder;
99  $store = true;
100  } else {
101  $this->expandFolder = $data['expandFolder'];
102  $store = false;
103  }
104  return array($data, $store);
105  }
106 
110  public function render()
111  {
112  $backendUser = $this->getBackendUser();
113 
114  // The key number 3 of the bparams contains the "allowed" string. Disallowed is not passed to
115  // the element browser at all but only filtered out in TCEMain afterwards
116  $allowedFileExtensions = explode('|', $this->bparams)[3];
117  if (!empty($allowedFileExtensions) && $allowedFileExtensions !== 'sys_file' && $allowedFileExtensions !== '*') {
118  // Create new filter object
119  $filterObject = GeneralUtility::makeInstance(FileExtensionFilter::class);
120  $filterObject->setAllowedFileExtensions($allowedFileExtensions);
121  // Set file extension filters on all storages
122  $storages = $backendUser->getFileStorages();
124  foreach ($storages as $storage) {
125  $storage->addFileAndFolderNameFilter(array($filterObject, 'filterFileList'));
126  }
127  }
128  // Create upload/create folder forms, if a path is given
129  if ($this->expandFolder) {
130  $fileOrFolderObject = null;
131 
132  // Try to fetch the folder the user had open the last time he browsed files
133  // Fallback to the default folder in case the last used folder is not existing
134  try {
135  $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
136  } catch (Exception $accessException) {
137  // We're just catching the exception here, nothing to be done if folder does not exist or is not accessible.
138  } catch (\InvalidArgumentException $driverMissingExecption) {
139  // We're just catching the exception here, nothing to be done if the driver does not exist anymore.
140  }
141 
142  if ($fileOrFolderObject instanceof Folder) {
143  // It's a folder
144  $this->selectedFolder = $fileOrFolderObject;
145  } elseif ($fileOrFolderObject instanceof FileInterface) {
146  // It's a file
147  $this->selectedFolder = $fileOrFolderObject->getParentFolder();
148  }
149  }
150  // Or get the user's default upload folder
151  if (!$this->selectedFolder) {
152  try {
153  $this->selectedFolder = $backendUser->getDefaultUploadFolder();
154  } catch (\Exception $e) {
155  // The configured default user folder does not exist
156  }
157  }
158  // Build the file upload and folder creation form
159  $uploadForm = '';
160  $createFolder = '';
161  if ($this->selectedFolder) {
162  $pArr = explode('|', $this->bparams);
163  $allowedExtensions = isset($pArr[3]) ? GeneralUtility::trimExplode(',', $pArr[3], true) : [];
164  $folderUtilityRenderer = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this);
165  $uploadForm = $folderUtilityRenderer->uploadForm($this->selectedFolder, $allowedExtensions);
166  $createFolder = $folderUtilityRenderer->createFolder($this->selectedFolder);
167  }
168 
169  // Getting flag for showing/not showing thumbnails:
170  $noThumbs = $backendUser->getTSConfigVal('options.noThumbsInEB');
171  $_MOD_SETTINGS = array();
172  if (!$noThumbs) {
173  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
174  $_MOD_MENU = array('displayThumbs' => '');
175  $_MCONF['name'] = 'file_list';
176  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
177  }
178  $noThumbs = $noThumbs ?: !$_MOD_SETTINGS['displayThumbs'];
179  // Create folder tree:
181  $folderTree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
182  $folderTree->setLinkParameterProvider($this);
183  $tree = $folderTree->getBrowsableTree();
184  if ($this->selectedFolder) {
185  $files = $this->renderFilesInFolder($this->selectedFolder, $allowedFileExtensions, $noThumbs);
186  } else {
187  $files = '';
188  }
189 
190  $this->initDocumentTemplate();
191  // Starting content:
192  $content = $this->doc->startPage('TBE file selector');
193  $content .= $this->doc->getFlashMessages();
194 
195  // Insert the upload form on top, if so configured
196  if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
197  $content .= $uploadForm;
198  }
199  // Putting the parts together, side by side:
200  $content .= '
201 
202  <!--
203  Wrapper table for folder tree / filelist:
204  -->
205  <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
206  <tr>
207  <td class="c-wCell" valign="top"><h3>' . $this->getLanguageService()->getLL('folderTree', true) . ':</h3>' . $tree . '</td>
208  <td class="c-wCell" valign="top">' . $files . '</td>
209  </tr>
210  </table>
211  ';
212  // Adding create folder + upload forms if applicable:
213  if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
214  $content .= $uploadForm;
215  }
216  $content .= $createFolder;
217  // Add some space
218  $content .= '<br /><br />';
219  // Ending page, returning content:
220  $content .= $this->doc->endPage();
221  return $this->doc->insertStylesAndJS($content);
222  }
223 
232  public function renderFilesInFolder(Folder $folder, $extensionList = '', $noThumbs = false)
233  {
234  if (!$folder->checkActionPermission('read')) {
235  return '';
236  }
237  $lang = $this->getLanguageService();
238  $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
239 
240  if ($this->searchWord !== '') {
241  $files = $this->fileRepository->searchByName($folder, $this->searchWord);
242  } else {
243  $extensionList = $extensionList === '*' ? '' : $extensionList;
244  $files = $this->getFilesInFolder($folder, $extensionList);
245  }
246  $filesCount = count($files);
247 
248  $lines = array();
249 
250  // Create the header of current folder:
251  $folderIcon = $this->iconFactory->getIconForResource($folder, Icon::SIZE_SMALL);
252  $lines[] = '<tr class="t3-row-header"><th colspan="4">'
253  . $folderIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), $titleLen))
254  . '</th></tr>';
255 
256  if ($filesCount === 0) {
257  $lines[] = '
258  <tr>
259  <td colspan="4">No files found.</td>
260  </tr>';
261  }
262 
263  foreach ($files as $fileObject) {
264  $fileExtension = $fileObject->getExtension();
265  // Thumbnail/size generation:
266  $imgInfo = array();
267  if (!$noThumbs && GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] . ',' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']), strtolower($fileExtension))) {
268  $processedFile = $fileObject->process(
270  array('width' => 64, 'height' => 64)
271  );
272  $imageUrl = $processedFile->getPublicUrl(true);
273  $imgInfo = array(
274  $fileObject->getProperty('width'),
275  $fileObject->getProperty('height')
276  );
277  $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
278  $clickIcon = '<img src="' . $imageUrl . '"'
279  . ' width="' . $processedFile->getProperty('width') . '"'
280  . ' height="' . $processedFile->getProperty('height') . '"'
281  . ' hspace="5" vspace="5" border="1" />';
282  } else {
283  $clickIcon = '';
284  $pDim = '';
285  }
286  // Create file icon:
287  $size = ' (' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes' . ($pDim ? ', ' . $pDim : '') . ')';
288  $icon = '<span title="' . htmlspecialchars($fileObject->getName() . $size) . '">' . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL) . '</span>';
289  // Create links for adding the file:
290  $filesIndex = count($this->elements);
291  $this->elements['file_' . $filesIndex] = array(
292  'type' => 'file',
293  'table' => 'sys_file',
294  'uid' => $fileObject->getUid(),
295  'fileName' => $fileObject->getName(),
296  'filePath' => $fileObject->getUid(),
297  'fileExt' => $fileExtension,
298  'fileIcon' => $icon
299  );
300  if ($this->fileIsSelectableInFileList($fileObject, $imgInfo)) {
301  $ATag = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="0">';
302  $ATag_alt = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="1">';
303  $ATag_e = '</a>';
304  $bulkCheckBox = '<input type="checkbox" class="typo3-bulk-item" name="file_' . $filesIndex . '" value="0" /> ';
305  } else {
306  $ATag = '';
307  $ATag_alt = '';
308  $ATag_e = '';
309  $bulkCheckBox = '';
310  }
311  // Create link to showing details about the file in a window:
312  $Ahref = BackendUtility::getModuleUrl('show_item', array(
313  'type' => 'file',
314  'table' => '_FILE',
315  'uid' => $fileObject->getCombinedIdentifier(),
316  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
317  ));
318 
319  // Combine the stuff:
320  $filenameAndIcon = $bulkCheckBox . $ATag_alt . $icon . htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $titleLen)) . $ATag_e;
321  // Show element:
322  $lines[] = '
323  <tr>
324  <td nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
325  <td>' . $ATag . '<span title="' . $lang->getLL('addToList', true) . '">' . $this->iconFactory->getIcon('actions-edit-add', Icon::SIZE_SMALL)->render() . '</span>' . $ATag_e . '</td>
326  <td nowrap="nowrap"><a href="' . htmlspecialchars($Ahref) . '" title="' . $lang->getLL('info', true) . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL) . $lang->getLL('info', true) . '</a></td>
327  <td nowrap="nowrap">&nbsp;' . $pDim . '</td>
328  </tr>';
329  if ($pDim) {
330  $lines[] = '
331  <tr>
332  <td class="filelistThumbnail" colspan="4">' . $ATag_alt . $clickIcon . $ATag_e . '</td>
333  </tr>';
334  }
335  }
336 
337  $out = '<h3>' . $lang->getLL('files', true) . ' ' . $filesCount . ':</h3>';
338  $out .= $this->getFileSearchField();
339  $out .= '<div id="filelist">';
340  $out .= $this->getBulkSelector($filesCount);
341 
342  // Wrap all the rows in table tags:
343  $out .= '
344 
345  <!--
346  Filelisting
347  -->
348  <table class="table table-striped table-hover" id="typo3-filelist">
349  ' . implode('', $lines) . '
350  </table>';
351  // Return accumulated content for filelisting:
352  $out .= '</div>';
353  return $out;
354  }
355 
363  protected function getFilesInFolder(Folder $folder, $extensionList)
364  {
365  if ($extensionList !== '') {
367  $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
368  $filter->setAllowedFileExtensions($extensionList);
369  $folder->setFileAndFolderNameFilters(array(array($filter, 'filterFileList')));
370  }
371  return $folder->getFiles();
372  }
373 
380  protected function getBulkSelector($filesCount)
381  {
382  if (!$filesCount) {
383  return '';
384  }
385 
386  $lang = $this->getLanguageService();
387  $labelToggleSelection = $lang->sL('LLL:EXT:lang/locallang_browse_links.xlf:toggleSelection', true);
388  $labelImportSelection = $lang->sL('LLL:EXT:lang/locallang_browse_links.xlf:importSelection', true);
389 
390  $out = '<div style="padding-top:10px;">' . '<a href="#" id="t3js-importSelection" title="' . $labelImportSelection . '">'
391  . $this->iconFactory->getIcon('actions-document-import-t3d', Icon::SIZE_SMALL)
392  . $labelImportSelection . '</a>&nbsp;&nbsp;&nbsp;'
393  . '<a href="#" id="t3js-toggleSelection" title="' . $labelToggleSelection . '">'
394  . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)
395  . $labelToggleSelection . '</a>' . '</div>';
396 
397  // Getting flag for showing/not showing thumbnails:
398  $noThumbsInEB = $this->getBackendUser()->getTSConfigVal('options.noThumbsInEB');
399  if (!$noThumbsInEB && $this->selectedFolder) {
400  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
401  $_MOD_MENU = array('displayThumbs' => '');
402  $_MCONF['name'] = 'file_list';
403  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
404  $addParams = GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters(['identifier' => $this->selectedFolder->getCombinedIdentifier()]));
405  $thumbNailCheck = '<div class="checkbox" style="padding:5px 0 15px 0"><label for="checkDisplayThumbs">'
407  '',
408  'SET[displayThumbs]',
409  $_MOD_SETTINGS['displayThumbs'],
410  $this->thisScript,
411  $addParams,
412  'id="checkDisplayThumbs"'
413  )
414  . $lang->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:displayThumbs', true) . '</label></div>';
415  $out .= $thumbNailCheck;
416  } else {
417  $out .= '<div style="padding-top: 15px;"></div>';
418  }
419  return $out;
420  }
421 
427  protected function getFileSearchField()
428  {
429  $action = $this->getScriptUrl() . GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters([]));
430  $out = '
431  <form method="post" action="' . htmlspecialchars($action) . '" style="padding-bottom: 15px;">
432  <div class="input-group">
433  <input class="form-control" type="text" name="searchWord" value="' . htmlspecialchars($this->searchWord) . '">
434  <span class="input-group-btn">
435  <button class="btn btn-default" type="submit">' . $this->getLanguageService()->sL('LLL:EXT:filelist/Resources/Private/Language/locallang.xlf:search', true) . '</button>
436  </span>
437  </div>
438  </form>';
439  return $out;
440  }
441 
451  protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
452  {
453  return true;
454  }
455 
459  protected function getBodyTagAttributes()
460  {
461  return [
462  'data-mode' => 'file',
463  'data-elements' => json_encode($this->elements)
464  ];
465  }
466 
471  public function getUrlParameters(array $values)
472  {
473  return [
474  'mode' => 'file',
475  'expandFolder' => isset($values['identifier']) ? $values['identifier'] : $this->expandFolder,
476  'bparams' => $this->bparams
477  ];
478  }
479 
484  public function isCurrentlySelectedItem(array $values)
485  {
486  return false;
487  }
488 
494  public function getScriptUrl()
495  {
496  return $this->thisScript;
497  }
498 }