TYPO3 CMS  TYPO3_8-7
FileBrowser.php
Go to the documentation of this file.
1 <?php
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 = [];
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 [$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 DataHandler afterwards
116  $allowedFileExtensions = GeneralUtility::trimExplode(',', explode('|', $this->bparams)[3], true);
117  if (!empty($allowedFileExtensions) && $allowedFileExtensions[0] !== 'sys_file' && $allowedFileExtensions[0] !== '*') {
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([$filterObject, 'filterFileList']);
126  }
127  }
128  if ($this->expandFolder) {
129  $fileOrFolderObject = null;
130 
131  // Try to fetch the folder the user had open the last time he browsed files
132  // Fallback to the default folder in case the last used folder is not existing
133  try {
134  $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
135  } catch (Exception $accessException) {
136  // We're just catching the exception here, nothing to be done if folder does not exist or is not accessible.
137  } catch (\InvalidArgumentException $driverMissingExecption) {
138  // We're just catching the exception here, nothing to be done if the driver does not exist anymore.
139  }
140 
141  if ($fileOrFolderObject instanceof Folder) {
142  // It's a folder
143  $this->selectedFolder = $fileOrFolderObject;
144  } elseif ($fileOrFolderObject instanceof FileInterface) {
145  // It's a file
146  $this->selectedFolder = $fileOrFolderObject->getParentFolder();
147  }
148  }
149  // Or get the user's default upload folder
150  if (!$this->selectedFolder) {
151  try {
152  list(, $pid, $table, , $field) = explode('-', explode('|', $this->bparams)[4]);
153  $this->selectedFolder = $backendUser->getDefaultUploadFolder($pid, $table, $field);
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  $folderUtilityRenderer = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this);
163  $uploadForm = $folderUtilityRenderer->uploadForm($this->selectedFolder, $allowedFileExtensions);
164  $createFolder = $folderUtilityRenderer->createFolder($this->selectedFolder);
165  }
166 
167  // Getting flag for showing/not showing thumbnails:
168  $noThumbs = $backendUser->getTSConfigVal('options.noThumbsInEB');
169  $_MOD_SETTINGS = [];
170  if (!$noThumbs) {
171  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
172  $_MOD_MENU = ['displayThumbs' => ''];
173  $_MCONF['name'] = 'file_list';
174  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
175  }
176  $displayThumbs = $_MOD_SETTINGS['displayThumbs'] ?? false;
177  $noThumbs = $noThumbs ?: !$displayThumbs;
178  // Create folder tree:
180  $folderTree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
181  $folderTree->setLinkParameterProvider($this);
182  $tree = $folderTree->getBrowsableTree();
183  if ($this->selectedFolder) {
184  $files = $this->renderFilesInFolder($this->selectedFolder, $allowedFileExtensions, $noThumbs);
185  } else {
186  $files = '';
187  }
188 
189  $this->initDocumentTemplate();
190  // Starting content:
191  $content = $this->doc->startPage(htmlspecialchars($this->getLanguageService()->getLL('fileSelector')));
192 
193  // Putting the parts together, side by side:
194  $markup = [];
195  $markup[] = '<!-- Wrapper table for folder tree / filelist: -->';
196  $markup[] = '<div class="element-browser">';
197  $markup[] = ' <div class="element-browser-panel element-browser-main">';
198  $markup[] = ' <div class="element-browser-main-sidebar">';
199  $markup[] = ' <div class="element-browser-body">';
200  $markup[] = ' <h3>' . htmlspecialchars($this->getLanguageService()->getLL('folderTree')) . ':</h3>';
201  $markup[] = ' ' . $tree;
202  $markup[] = ' </div>';
203  $markup[] = ' </div>';
204  $markup[] = ' <div class="element-browser-main-content">';
205  $markup[] = ' <div class="element-browser-body">';
206  $markup[] = ' ' . $this->doc->getFlashMessages();
207  $markup[] = ' ' . $files;
208  $markup[] = ' ' . $uploadForm;
209  $markup[] = ' ' . $createFolder;
210  $markup[] = ' </div>';
211  $markup[] = ' </div>';
212  $markup[] = ' </div>';
213  $markup[] = '</div>';
214  $content .= implode('', $markup);
215 
216  // Ending page, returning content:
217  $content .= $this->doc->endPage();
218  return $this->doc->insertStylesAndJS($content);
219  }
220 
229  public function renderFilesInFolder(Folder $folder, array $extensionList = [], $noThumbs = false)
230  {
231  if (!$folder->checkActionPermission('read')) {
232  return '';
233  }
234  $lang = $this->getLanguageService();
235  $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
236 
237  if ($this->searchWord !== '') {
238  $files = $this->fileRepository->searchByName($folder, $this->searchWord);
239  } else {
240  $extensionList = !empty($extensionList) && $extensionList[0] === '*' ? [] : $extensionList;
241  $files = $this->getFilesInFolder($folder, $extensionList);
242  }
243  $filesCount = count($files);
244 
245  $lines = [];
246 
247  // Create the header of current folder:
248  $folderIcon = $this->iconFactory->getIconForResource($folder, Icon::SIZE_SMALL);
249 
250  $lines[] = '
251  <tr>
252  <th class="col-title nowrap">' . $folderIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getStorage()->getName() . ':' . $folder->getReadablePath(), $titleLen)) . '</th>
253  <th class="col-control nowrap"></th>
254  <th class="col-clipboard nowrap">
255  <a href="#" class="btn btn-default" id="t3js-importSelection" title="' . htmlspecialchars($lang->getLL('importSelection')) . '">' . $this->iconFactory->getIcon('actions-document-import-t3d', Icon::SIZE_SMALL) . '</a>
256  <a href="#" class="btn btn-default" id="t3js-toggleSelection" title="' . htmlspecialchars($lang->getLL('toggleSelection')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL) . '</a>
257  </th>
258  <th class="nowrap">&nbsp;</th>
259  </tr>';
260 
261  if ($filesCount === 0) {
262  $lines[] = '
263  <tr>
264  <td colspan="4">No files found.</td>
265  </tr>';
266  }
267 
268  foreach ($files as $fileObject) {
269  $fileExtension = $fileObject->getExtension();
270  // Thumbnail/size generation:
271  $imgInfo = [];
272  if (!$noThumbs && GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] . ',' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']), strtolower($fileExtension))) {
273  $processedFile = $fileObject->process(
275  ['width' => 64, 'height' => 64]
276  );
277  $imageUrl = $processedFile->getPublicUrl(true);
278  $imgInfo = [
279  $fileObject->getProperty('width'),
280  $fileObject->getProperty('height')
281  ];
282  $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
283  $clickIcon = '<img src="' . $imageUrl . '"'
284  . ' width="' . $processedFile->getProperty('width') . '"'
285  . ' height="' . $processedFile->getProperty('height') . '"'
286  . ' hspace="5" vspace="5" border="1" />';
287  } else {
288  $clickIcon = '';
289  $pDim = '';
290  }
291  // Create file icon:
292  $size = ' (' . GeneralUtility::formatSize($fileObject->getSize(), $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:byteSizeUnits')) . ($pDim ? ', ' . $pDim : '') . ')';
293  $icon = '<span title="' . htmlspecialchars($fileObject->getName() . $size) . '">' . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL) . '</span>';
294  // Create links for adding the file:
295  $filesIndex = count($this->elements);
296  $this->elements['file_' . $filesIndex] = [
297  'type' => 'file',
298  'table' => 'sys_file',
299  'uid' => $fileObject->getUid(),
300  'fileName' => $fileObject->getName(),
301  'filePath' => $fileObject->getUid(),
302  'fileExt' => $fileExtension,
303  'fileIcon' => $icon
304  ];
305  if ($this->fileIsSelectableInFileList($fileObject, $imgInfo)) {
306  $ATag = '<a href="#" class="btn btn-default" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="0">';
307  $ATag .= '<span title="' . htmlspecialchars($lang->getLL('addToList')) . '">' . $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render() . '</span>';
308  $ATag_alt = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="1">';
309  $ATag_e = '</a>';
310  $bulkCheckBox = '<label class="btn btn-default btn-checkbox"><input type="checkbox" class="typo3-bulk-item" name="file_' . $filesIndex . '" value="0" /><span class="t3-icon fa"></span></label>';
311  } else {
312  $ATag = '';
313  $ATag_alt = '';
314  $ATag_e = '';
315  $bulkCheckBox = '';
316  }
317  // Create link to showing details about the file in a window:
318  $Ahref = BackendUtility::getModuleUrl('show_item', [
319  'type' => 'file',
320  'table' => '_FILE',
321  'uid' => $fileObject->getCombinedIdentifier(),
322  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
323  ]);
324 
325  // Combine the stuff:
326  $filenameAndIcon = $ATag_alt . $icon . htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $titleLen)) . $ATag_e;
327  // Show element:
328  $lines[] = '
329  <tr class="file_list_normal">
330  <td class="col-title nowrap">' . $filenameAndIcon . '&nbsp;</td>
331  <td class="col-control">
332  <div class="btn-group">' . $ATag . $ATag_e . '
333  <a href="' . htmlspecialchars($Ahref) . '" class="btn btn-default" title="' . htmlspecialchars($lang->getLL('info')) . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL) . '</a>
334  </td>
335  <td class="col-clipboard" valign="top">' . $bulkCheckBox . '</td>
336  <td class="nowrap">&nbsp;' . $pDim . '</td>
337  </tr>';
338  if ($pDim) {
339  $lines[] = '
340  <tr>
341  <td class="filelistThumbnail" colspan="4">' . $ATag_alt . $clickIcon . $ATag_e . '</td>
342  </tr>';
343  }
344  }
345 
346  $markup = [];
347  $markup[] = '<h3>' . htmlspecialchars($lang->getLL('files')) . ' ' . $filesCount . ':</h3>';
348  $markup[] = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this)->getFileSearchField($this->searchWord);
349  $markup[] = '<div id="filelist">';
350  $markup[] = ' ' . $this->getBulkSelector($filesCount);
351  $markup[] = ' <!-- Filelisting -->';
352  $markup[] = ' <div class="table-fit">';
353  $markup[] = ' <table class="table table-striped table-hover" id="typo3-filelist">';
354  $markup[] = ' ' . implode('', $lines);
355  $markup[] = ' </table>';
356  $markup[] = ' </div>';
357  $markup[] = ' </div>';
358  $content = implode('', $markup);
359 
360  return $content;
361  }
362 
370  protected function getFilesInFolder(Folder $folder, array $extensionList)
371  {
372  if (!empty($extensionList)) {
374  $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
375  $filter->setAllowedFileExtensions($extensionList);
376  $folder->setFileAndFolderNameFilters([[$filter, 'filterFileList']]);
377  }
378  return $folder->getFiles();
379  }
380 
387  protected function getBulkSelector($filesCount)
388  {
389  if (!$filesCount) {
390  return '';
391  }
392 
393  $lang = $this->getLanguageService();
394  $out = '';
395 
396  // Getting flag for showing/not showing thumbnails:
397  $noThumbsInEB = $this->getBackendUser()->getTSConfigVal('options.noThumbsInEB');
398  if (!$noThumbsInEB && $this->selectedFolder) {
399  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
400  $_MOD_MENU = ['displayThumbs' => ''];
401  $_MCONF['name'] = 'file_list';
402  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
403  $addParams = GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters(['identifier' => $this->selectedFolder->getCombinedIdentifier()]));
404  $thumbNailCheck = '<div class="checkbox" style="padding:5px 0 15px 0"><label for="checkDisplayThumbs">'
406  '',
407  'SET[displayThumbs]',
408  $_MOD_SETTINGS['displayThumbs'],
409  $this->thisScript,
410  $addParams,
411  'id="checkDisplayThumbs"'
412  )
413  . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_file_list.xlf:displayThumbs')) . '</label></div>';
414  $out .= $thumbNailCheck;
415  } else {
416  $out .= '<div style="padding-top: 15px;"></div>';
417  }
418  return $out;
419  }
420 
430  protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
431  {
432  return true;
433  }
434 
438  protected function getBodyTagAttributes()
439  {
440  return [
441  'data-mode' => 'file',
442  'data-elements' => json_encode($this->elements)
443  ];
444  }
445 
450  public function getUrlParameters(array $values)
451  {
452  return [
453  'mode' => 'file',
454  'expandFolder' => isset($values['identifier']) ? $values['identifier'] : $this->expandFolder,
455  'bparams' => $this->bparams
456  ];
457  }
458 
463  public function isCurrentlySelectedItem(array $values)
464  {
465  return false;
466  }
467 
473  public function getScriptUrl()
474  {
475  return $this->thisScript;
476  }
477 }
setFileAndFolderNameFilters(array $filters)
Definition: Folder.php:494
static getModuleData( $MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
renderFilesInFolder(Folder $folder, array $extensionList=[], $noThumbs=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
getReadablePath($rootId=null)
Definition: Folder.php:105
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
getFiles($start=0, $numberOfItems=0, $filterMode=self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive=false, $sort='', $sortRev=false)
Definition: Folder.php:217
static getFuncCheck( $mainParams, $elementName, $currentValue, $script='', $addParams='', $tagParams='')
static fixed_lgd_cs($string, $chars, $appendString='...')
static formatSize($sizeInBytes, $labels='', $base=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']