TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
AddImageHandler.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\ImageHandler;
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;
39 
41 {
47  protected $mode;
48 
53 
59  protected $plainMaxWidth;
60 
66  protected $plainMaxHeight;
67 
71  protected $expandFolder;
72 
76  protected $defaultClass;
77 
81  protected $selectedFolder;
82 
88  protected $elements = [];
89 
93  protected $searchWord;
94 
98  protected $fileRepository;
99 
105  protected $thisScript = '';
106 
110  protected $iconFactory;
111 
122  public function initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration)
123  {
124  $this->fileRepository = GeneralUtility::makeInstance(FileRepository::class);
125  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
126 
127  $this->expandFolder = GeneralUtility::_GP('expandFolder');
128  $this->searchWord = (string)GeneralUtility::_GP('searchWord');
129 
130  if ($identifier !== 'plain' && $identifier !== 'magic') {
131  throw new \InvalidArgumentException('The given identifier "' . $identifier . '" is not supported by this handler."', 1455499720);
132  }
133  if (!$linkBrowser instanceof SelectImageController) {
134  throw new \InvalidArgumentException('The given $linkBrowser must be of type SelectImageController."', 1455499721);
135  }
136  $this->mode = $identifier;
137  $this->selectImageController = $linkBrowser;
138 
139  $buttonConfiguration = $linkBrowser->getButtonConfiguration();
140  $this->plainMaxWidth = empty($buttonConfiguration['options.']['plain.']['maxWidth'])
141  ? 640
142  : $buttonConfiguration['options.']['plain.']['maxWidth'];
143  $this->plainMaxHeight = empty($buttonConfiguration['options.']['plain.']['maxHeight'])
144  ? 680
145  : $buttonConfiguration['options.']['plain.']['maxHeight'];
146 
147  $this->getLanguageService()->includeLLFile('EXT:rtehtmlarea/Resources/Private/Language/locallang_selectimagecontroller.xlf');
148  }
149 
157  public function render(ServerRequestInterface $request)
158  {
159  GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Rtehtmlarea/AddImage');
160 
161  $backendUser = $this->getBackendUser();
162 
163  // The key number 3 of the bparams contains the "allowed" string. Disallowed is not passed to
164  // the element browser at all but only filtered out in DataHandler afterwards
165  $bparams = explode('|', $this->selectImageController->getUrlParameters()['bparams']);
166  if (isset($bparams[3])) {
167  $allowedFileExtensions = GeneralUtility::trimExplode(',', $bparams[3], true);
168  } else {
169  $allowedFileExtensions = GeneralUtility::trimExplode(
170  ',',
171  $this->mode === 'plain'
173  : $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
174  true
175  );
176  }
177  if (!empty($allowedFileExtensions) && $allowedFileExtensions[0] !== 'sys_file' && $allowedFileExtensions[0] !== '*') {
178  // Create new filter object
179  $filterObject = GeneralUtility::makeInstance(FileExtensionFilter::class);
180  $filterObject->setAllowedFileExtensions($allowedFileExtensions);
181  // Set file extension filters on all storages
182  $storages = $backendUser->getFileStorages();
184  foreach ($storages as $storage) {
185  $storage->addFileAndFolderNameFilter([$filterObject, 'filterFileList']);
186  }
187  }
188  if ($this->expandFolder) {
189  $fileOrFolderObject = null;
190 
191  // Try to fetch the folder the user had open the last time he browsed files
192  // Fallback to the default folder in case the last used folder is not existing
193  try {
194  $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
195  } catch (Exception $accessException) {
196  // We're just catching the exception here, nothing to be done if folder does not exist or is not accessible.
197  } catch (\InvalidArgumentException $driverMissingExecption) {
198  // We're just catching the exception here, nothing to be done if the driver does not exist anymore.
199  }
200 
201  if ($fileOrFolderObject instanceof Folder) {
202  // It's a folder
203  $this->selectedFolder = $fileOrFolderObject;
204  } elseif ($fileOrFolderObject instanceof FileInterface) {
205  // It's a file
206  $this->selectedFolder = $fileOrFolderObject->getParentFolder();
207  }
208  }
209  // Or get the user's default upload folder
210  if (!$this->selectedFolder) {
211  try {
212  $this->selectedFolder = $backendUser->getDefaultUploadFolder();
213  } catch (\Exception $e) {
214  // The configured default user folder does not exist
215  }
216  }
217  // Build the file upload and folder creation form
218  $uploadForm = '';
219  $createFolder = '';
220  if ($this->selectedFolder) {
221  $folderUtilityRenderer = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this);
222  $uploadForm = $folderUtilityRenderer->uploadForm($this->selectedFolder, $allowedFileExtensions);
223  $createFolder = $folderUtilityRenderer->createFolder($this->selectedFolder);
224  }
225 
226  // Getting flag for showing/not showing thumbnails:
227  $noThumbs = $backendUser->getTSConfigVal('options.noThumbsInRTEimageSelect');
228  $_MOD_SETTINGS = [];
229  if (!$noThumbs) {
230  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
231  $_MOD_MENU = ['displayThumbs' => ''];
232  $_MCONF['name'] = 'file_list';
233  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
234  }
235  $noThumbs = $noThumbs ?: !$_MOD_SETTINGS['displayThumbs'];
236  // Create folder tree:
238  $folderTree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
239  $folderTree->setLinkParameterProvider($this);
240  $tree = $folderTree->getBrowsableTree();
241  if ($this->selectedFolder) {
242  $files = $this->renderFilesInFolder($this->selectedFolder, $allowedFileExtensions, $noThumbs);
243  } else {
244  $files = '';
245  }
246 
247  $content = '';
248  // Insert the upload form on top, if so configured
249  if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
250  $content .= $uploadForm;
251  }
252  // Putting the parts together, side by side:
253  $content .= '
254 
255  <!--
256  Wrapper table for folder tree / filelist:
257  -->
258  <div class="element-browser-section element-browser-filetree">
259  <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
260  <tr>
261  <td class="c-wCell" valign="top"><h3>' . htmlspecialchars($this->getLanguageService()->getLL('folderTree')) . ':</h3>' . $tree . '</td>
262  <td class="c-wCell" valign="top">' . $files . '</td>
263  </tr>
264  </table>
265  </div>
266  ';
267  // Add help message
268  switch ($this->mode) {
269  case 'plain':
270  $content .= sprintf($this->getLanguageService()->getLL('plainImage_msg'), $this->plainMaxWidth, $this->plainMaxHeight);
271  break;
272  case 'magic':
273  $content .= sprintf($this->getLanguageService()->getLL('magicImage_msg'));
274  break;
275  }
276  // Adding create folder + upload forms if applicable:
277  if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
278  $content .= $uploadForm;
279  }
280  $content .= $createFolder;
281  // Add some space
282  $content .= '<br /><br />';
283 
284  return $content;
285  }
286 
295  public function renderFilesInFolder(Folder $folder, array $extensionList = [], $noThumbs = false)
296  {
297  if (!$folder->checkActionPermission('read')) {
298  return '';
299  }
300  $lang = $this->getLanguageService();
301  $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
302 
303  if ($this->searchWord !== '') {
304  $files = $this->fileRepository->searchByName($folder, $this->searchWord);
305  } else {
306  $extensionList = !empty($extensionList) && $extensionList[0] === '*' ? [] : $extensionList;
307  $files = $this->getFilesInFolder($folder, $extensionList);
308  }
309  $filesCount = count($files);
310 
311  $lines = [];
312 
313  // Create the header of current folder:
314  $folderIcon = $this->iconFactory->getIconForResource($folder, Icon::SIZE_SMALL);
315 
316  $lines[] = '
317  <tr>
318  <th class="col-title" nowrap="nowrap">' . $folderIcon . ' ' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), $titleLen)) . '</th>
319  <th class="col-control" nowrap="nowrap"></th>
320  <th class="col-clipboard" nowrap="nowrap">
321  <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>
322  <a href="#" class="btn btn-default" id="t3js-toggleSelection" title="' . htmlspecialchars($lang->getLL('toggleSelection')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL) . '</a>
323  </th>
324  <th nowrap="nowrap">&nbsp;</th>
325  </tr>';
326 
327  if ($filesCount === 0) {
328  $lines[] = '
329  <tr>
330  <td colspan="4">No files found.</td>
331  </tr>';
332  }
333 
334  foreach ($files as $fileObject) {
335  $fileExtension = $fileObject->getExtension();
336  // Thumbnail/size generation:
337  $imgInfo = [];
338  if (!$noThumbs && GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] . ',' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']), strtolower($fileExtension))) {
339  $processedFile = $fileObject->process(
341  ['width' => 64, 'height' => 64]
342  );
343  $imageUrl = $processedFile->getPublicUrl(true);
344  $imgInfo = [
345  $fileObject->getProperty('width'),
346  $fileObject->getProperty('height')
347  ];
348  $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
349  $clickIcon = '<img src="' . $imageUrl . '"'
350  . ' width="' . $processedFile->getProperty('width') . '"'
351  . ' height="' . $processedFile->getProperty('height') . '"'
352  . ' hspace="5" vspace="5" border="1" />';
353  } else {
354  $clickIcon = '';
355  $pDim = '';
356  }
357  // Create file icon:
358  $size = ' (' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes' . ($pDim ? ', ' . $pDim : '') . ')';
359  $icon = '<span title="' . htmlspecialchars($fileObject->getName() . $size) . '">' . $this->iconFactory->getIconForResource($fileObject, Icon::SIZE_SMALL) . '</span>';
360  // Create links for adding the file:
361  $filesIndex = count($this->elements);
362  $this->elements['file_' . $filesIndex] = [
363  'type' => 'file',
364  'table' => 'sys_file',
365  'uid' => $fileObject->getUid(),
366  'fileName' => $fileObject->getName(),
367  'filePath' => $fileObject->getUid(),
368  'fileExt' => $fileExtension,
369  'fileIcon' => $icon
370  ];
371  if ($this->fileIsSelectableInFileList($fileObject, $imgInfo)) {
372  $ATag = '<a href="#" class="btn btn-default" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="0">';
373  $ATag_alt = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" data-file-index="' . htmlspecialchars($filesIndex) . '" data-close="1">';
374  $ATag_e = '</a>';
375  $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>';
376  } else {
377  $ATag = '';
378  $ATag_alt = '';
379  $ATag_e = '';
380  $bulkCheckBox = '';
381  }
382  // Create link to showing details about the file in a window:
383  $Ahref = BackendUtility::getModuleUrl('show_item', [
384  'type' => 'file',
385  'table' => '_FILE',
386  'uid' => $fileObject->getCombinedIdentifier(),
387  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
388  ]);
389 
390  // Combine the stuff:
391  $filenameAndIcon = $ATag_alt . $icon . htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $titleLen)) . $ATag_e;
392  // Show element:
393  $lines[] = '
394  <tr class="file_list_normal">
395  <td class="col-title" nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
396  <td class="col-control">
397  <div class="btn-group">' . $ATag . '<span title="' . htmlspecialchars($lang->getLL('addToList')) . '">' . $this->iconFactory->getIcon('actions-edit-add', Icon::SIZE_SMALL)->render() . '</span>' . $ATag_e . '
398  <a href="' . htmlspecialchars($Ahref) . '" class="btn btn-default" title="' . htmlspecialchars($lang->getLL('info')) . '">' . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL) . '</a>
399  </td>
400  <td class="col-clipboard" valign="top">' . $bulkCheckBox . '</td>
401  <td nowrap="nowrap">&nbsp;' . $pDim . '</td>
402  </tr>';
403  if ($pDim) {
404  $lines[] = '
405  <tr>
406  <td class="filelistThumbnail" colspan="4">' . $ATag_alt . $clickIcon . $ATag_e . '</td>
407  </tr>';
408  }
409  }
410 
411  $out = '<h3>' . htmlspecialchars($lang->getLL('files')) . ' ' . $filesCount . ':</h3>';
412  $out .= GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this)->getFileSearchField($this->searchWord);
413  $out .= '<div id="filelist">';
414  $out .= $this->getBulkSelector($filesCount);
415 
416  // Wrap all the rows in table tags:
417  $out .= '
418 
419  <!--
420  Filelisting
421  -->
422  <table class="table table-striped table-hover" id="typo3-filelist">
423  ' . implode('', $lines) . '
424  </table>';
425  // Return accumulated content for filelisting:
426  $out .= '</div>';
427  return $out;
428  }
429 
437  protected function getFilesInFolder(Folder $folder, array $extensionList)
438  {
439  if (!empty($extensionList)) {
441  $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
442  $filter->setAllowedFileExtensions($extensionList);
443  $folder->setFileAndFolderNameFilters([[$filter, 'filterFileList']]);
444  }
445  return $folder->getFiles();
446  }
447 
454  protected function getBulkSelector($filesCount)
455  {
456  if (!$filesCount) {
457  return '';
458  }
459 
460  $lang = $this->getLanguageService();
461  $out = '';
462 
463  // Getting flag for showing/not showing thumbnails:
464  $noThumbsInEB = $this->getBackendUser()->getTSConfigVal('options.noThumbsInEB');
465  if (!$noThumbsInEB && $this->selectedFolder) {
466  // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
467  $_MOD_MENU = ['displayThumbs' => ''];
468  $_MCONF['name'] = 'file_list';
469  $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
470  $addParams = GeneralUtility::implodeArrayForUrl('', $this->getUrlParameters(['identifier' => $this->selectedFolder->getCombinedIdentifier()]));
471  $thumbNailCheck = '<div class="checkbox" style="padding:5px 0 15px 0"><label for="checkDisplayThumbs">'
473  '',
474  'SET[displayThumbs]',
475  $_MOD_SETTINGS['displayThumbs'],
476  $this->thisScript,
477  $addParams,
478  'id="checkDisplayThumbs"'
479  )
480  . htmlspecialchars($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_mod_file_list.xlf:displayThumbs')) . '</label></div>';
481  $out .= $thumbNailCheck;
482  } else {
483  $out .= '<div style="padding-top: 15px;"></div>';
484  }
485  return $out;
486  }
487 
497  protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
498  {
499  return $this->mode !== 'plain'
501  && $imgInfo[0] <= $this->plainMaxWidth && $imgInfo[1] <= $this->plainMaxHeight);
502  }
503 
507  public function getBodyTagAttributes()
508  {
509  return [
510  'data-elements' => json_encode($this->elements)
511  ];
512  }
513 
519  public function getScriptUrl()
520  {
521  return $this->selectImageController->getScriptUrl();
522  }
523 
531  public function getUrlParameters(array $values)
532  {
533  $parameters = [
534  'expandFolder' => isset($values['identifier']) ? $values['identifier'] : (string)$this->expandFolder
535  ];
536  return array_merge($this->selectImageController->getUrlParameters($values), $parameters);
537  }
538 
546  public function isUpdateSupported()
547  {
548  return false;
549  }
550 
554  public function getLinkAttributes()
555  {
556  return [];
557  }
558 
563  public function modifyLinkAttributes(array $fieldDefinitions)
564  {
565  return $fieldDefinitions;
566  }
567 
577  public function isCurrentlySelectedItem(array $values)
578  {
579  return false;
580  }
581 
591  public function canHandleLink(array $linkParts)
592  {
593  return false;
594  }
595 
601  public function formatCurrentUrl()
602  {
603  return '';
604  }
605 
609  protected function getLanguageService()
610  {
611  return $GLOBALS['LANG'];
612  }
613 
617  protected function getBackendUser()
618  {
619  return $GLOBALS['BE_USER'];
620  }
621 }
getFiles($start=0, $numberOfItems=0, $filterMode=self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive=false, $sort= '', $sortRev=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
static implodeArrayForUrl($name, array $theArray, $str= '', $skipBlank=false, $rawurlencodeParamName=false)
renderFilesInFolder(Folder $folder, array $extensionList=[], $noThumbs=false)
static formatSize($sizeInBytes, $labels= '', $base=0)
static getModuleData($MOD_MENU, $CHANGED_SETTINGS, $modName, $type= '', $dontValidateList= '', $setDefaultList= '')
static getFuncCheck($mainParams, $elementName, $currentValue, $script= '', $addParams= '', $tagParams= '')
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration)