TYPO3  7.6
ExtendedFileUtility.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Utility\File;
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 
24 use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
31 use TYPO3\CMS\Core\Type\Exception\InvalidEnumerationValueException;
32 
60 {
68  public $unzipPath = '';
69 
76  public $dontCheckForUnique = 0;
77 
85 
93  public $actionPerms = array(
94  // File permissions
95  'addFile' => false,
96  'readFile' => false,
97  'writeFile' => false,
98  'copyFile' => false,
99  'moveFile' => false,
100  'renameFile' => false,
101  'unzipFile' => false,
102  'deleteFile' => false,
103  // Folder permissions
104  'addFolder' => false,
105  'readFolder' => false,
106  'writeFolder' => false,
107  'copyFolder' => false,
108  'moveFolder' => false,
109  'renameFolder' => false,
110  'deleteFolder' => false,
111  'recursivedeleteFolder' => false
112  );
113 
119  public $recyclerFN = '_recycler_';
120 
126  public $internalUploadMap = array();
127 
131  public $lastError = '';
132 
138  protected $errorMessages = array();
139 
143  protected $fileCmdMap;
144 
150  protected $fileFactory;
151 
158  {
159  return (string)$this->existingFilesConflictMode;
160  }
161 
170  {
171  try {
172  $this->existingFilesConflictMode = DuplicationBehavior::cast($existingFilesConflictMode);
173  } catch (InvalidEnumerationValueException $e) {
174  throw new Exception(
175  sprintf(
176  'Invalid argument, received: "%s", expected a value from enumeration \TYPO3\CMS\Core\Resource\DuplicationBehavior (%s)',
178  implode(', ', DuplicationBehavior::getConstants())
179  )
180  );
181  }
182  }
183 
190  public function start($fileCmds)
191  {
192  $unzipPath = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path']);
193  if (substr($unzipPath, -1) !== '/' && is_dir($unzipPath)) {
194  // Make sure the path ends with a slash
195  $unzipPath .= '/';
196  }
197  $this->unzipPath = $unzipPath;
198  // Initialize Object Factory
199  $this->fileFactory = ResourceFactory::getInstance();
200  // Initializing file processing commands:
201  $this->fileCmdMap = $fileCmds;
202  }
203 
211  public function setActionPermissions(array $permissions = array())
212  {
213  if (empty($permissions)) {
214  $permissions = $GLOBALS['BE_USER']->getFilePermissions();
215  }
216  $this->actionPerms = $permissions;
217  }
218 
225  public function processData()
226  {
227  $result = array();
228  if (!$this->isInit) {
229  return false;
230  }
231  if (is_array($this->fileCmdMap)) {
232  // Check if there were uploads expected, but no one made
233  if ($this->fileCmdMap['upload']) {
234  $uploads = $this->fileCmdMap['upload'];
235  foreach ($uploads as $upload) {
236  if (empty($_FILES[('upload_' . $upload['data'])]['name'])
237  || (is_array($_FILES[('upload_' . $upload['data'])]['name'])
238  && empty($_FILES[('upload_' . $upload['data'])]['name'][0])
239  )
240  ) {
241  unset($this->fileCmdMap['upload'][$upload['data']]);
242  }
243  }
244  if (empty($this->fileCmdMap['upload'])) {
245  $this->writelog(1, 1, 108, 'No file was uploaded!', '');
246  }
247  }
248 
249  // Check if there were new folder names expected, but non given
250  if ($this->fileCmdMap['newfolder']) {
251  foreach ($this->fileCmdMap['newfolder'] as $key => $cmdArr) {
252  if (empty($cmdArr['data'])) {
253  unset($this->fileCmdMap['newfolder'][$key]);
254  }
255  }
256  if (empty($this->fileCmdMap['newfolder'])) {
257  $this->writeLog(6, 1, 108, 'No name for new folder given!', '');
258  }
259  }
260 
261  // Traverse each set of actions
262  foreach ($this->fileCmdMap as $action => $actionData) {
263  // Traverse all action data. More than one file might be affected at the same time.
264  if (is_array($actionData)) {
265  $result[$action] = array();
266  foreach ($actionData as $cmdArr) {
267  // Clear file stats
268  clearstatcache();
269  // Branch out based on command:
270  switch ($action) {
271  case 'delete':
272  $result[$action][] = $this->func_delete($cmdArr);
273  break;
274  case 'copy':
275  $result[$action][] = $this->func_copy($cmdArr);
276  break;
277  case 'move':
278  $result[$action][] = $this->func_move($cmdArr);
279  break;
280  case 'rename':
281  $result[$action][] = $this->func_rename($cmdArr);
282  break;
283  case 'newfolder':
284  $result[$action][] = $this->func_newfolder($cmdArr);
285  break;
286  case 'newfile':
287  $result[$action][] = $this->func_newfile($cmdArr);
288  break;
289  case 'editfile':
290  $result[$action][] = $this->func_edit($cmdArr);
291  break;
292  case 'upload':
293  $result[$action][] = $this->func_upload($cmdArr);
294  break;
295  case 'replace':
296  $result[$action][] = $this->replaceFile($cmdArr);
297  break;
298  case 'unzip':
299  $result[$action][] = $this->func_unzip($cmdArr);
300  break;
301  }
302  // Hook for post-processing the action
303  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_extfilefunc.php']['processData'])) {
304  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_extfilefunc.php']['processData'] as $classRef) {
305  $hookObject = GeneralUtility::getUserObj($classRef);
306  if (!$hookObject instanceof ExtendedFileUtilityProcessDataHookInterface) {
307  throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Core\\Utility\\File\\ExtendedFileUtilityProcessDataHookInterface', 1279719168);
308  }
309  $hookObject->processData_postProcessAction($action, $cmdArr, $result[$action], $this);
310  }
311  }
312  }
313  }
314  }
315  }
316  return $result;
317  }
318 
325  {
326  foreach ($this->getErrorMessages() as $msg) {
327  $flashMessage = GeneralUtility::makeInstance(
328  FlashMessage::class,
329  $msg,
330  '',
332  true
333  );
334  $this->addFlashMessage($flashMessage);
335  }
336  }
337 
343  public function getErrorMessages()
344  {
345  return $this->errorMessages;
346  }
347 
356  public function writeLog($action, $error, $details_nr, $details, $data)
357  {
358  // Type value for tce_file.php
359  $type = 2;
360  if (is_object($this->getBackendUser())) {
361  $this->getBackendUser()->writelog($type, $action, $error, $details_nr, $details, $data);
362  }
363  if ($error > 0) {
364  $this->lastError = vsprintf($details, $data);
365  $this->errorMessages[] = $this->lastError;
366  }
367  }
368 
369  /*************************************
370  *
371  * File operation functions
372  *
373  **************************************/
380  public function func_delete(array $cmds)
381  {
382  $result = false;
383  if (!$this->isInit) {
384  return $result;
385  }
386  // Example indentifier for $cmds['data'] => "4:mypath/tomyfolder/myfile.jpg"
387  // for backwards compatibility: the combined file identifier was the path+filename
388  try {
389  $fileObject = $this->getFileObject($cmds['data']);
390  } catch (ResourceDoesNotExistException $e) {
391  $flashMessage = GeneralUtility::makeInstance(
392  FlashMessage::class,
393  sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileNotFound'), $cmds['data']),
394  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileNotFound'),
396  true
397  );
398  $this->addFlashMessage($flashMessage);
399 
400  return false;
401  }
402  // @todo implement the recycler feature which has been removed from the original implementation
403  // checks to delete the file
404  if ($fileObject instanceof File) {
405  // check if the file still has references
406  // Exclude sys_file_metadata records as these are no use references
407  $databaseConnection = $this->getDatabaseConnection();
408  $table = 'sys_refindex';
409  $refIndexRecords = $databaseConnection->exec_SELECTgetRows(
410  '*',
411  $table,
412  'deleted=0 AND ref_table=' . $databaseConnection->fullQuoteStr('sys_file', $table)
413  . ' AND ref_uid=' . (int)$fileObject->getUid()
414  . ' AND tablename != ' . $databaseConnection->fullQuoteStr('sys_file_metadata', $table)
415  );
416  $deleteFile = true;
417  if (!empty($refIndexRecords)) {
418  $shortcutContent = array();
419  $brokenReferences = array();
420 
421  foreach ($refIndexRecords as $fileReferenceRow) {
422  if ($fileReferenceRow['tablename'] === 'sys_file_reference') {
423  $row = $this->transformFileReferenceToRecordReference($fileReferenceRow);
424  $shortcutRecord = BackendUtility::getRecord($row['tablename'], $row['recuid']);
425 
426  if ($shortcutRecord) {
427  $shortcutContent[] = '[record:' . $row['tablename'] . ':' . $row['recuid'] . ']';
428  } else {
429  $brokenReferences[] = $fileReferenceRow['ref_uid'];
430  }
431  }
432  }
433  if (!empty($brokenReferences)) {
434  // render a message that the file has broken references
435  $flashMessage = GeneralUtility::makeInstance(
436  FlashMessage::class,
437  sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileHasBrokenReferences'), count($brokenReferences)),
438  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileHasBrokenReferences'),
440  true
441  );
442  $this->addFlashMessage($flashMessage);
443  }
444  if (!empty($shortcutContent)) {
445  // render a message that the file could not be deleted
446  $flashMessage = GeneralUtility::makeInstance(
447  FlashMessage::class,
448  sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileNotDeletedHasReferences'), $fileObject->getName()) . ' ' . implode(', ', $shortcutContent),
449  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileNotDeletedHasReferences'),
451  true
452  );
453  $this->addFlashMessage($flashMessage);
454  $deleteFile = false;
455  }
456  }
457 
458  if ($deleteFile) {
459  try {
460  $result = $fileObject->delete();
461 
462  // show the user that the file was deleted
463  $flashMessage = GeneralUtility::makeInstance(
464  FlashMessage::class,
465  sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileDeleted'), $fileObject->getName()),
466  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileDeleted'),
468  true
469  );
470  $this->addFlashMessage($flashMessage);
471  // Log success
472  $this->writelog(4, 0, 1, 'File "%s" deleted', array($fileObject->getIdentifier()));
473  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
474  $this->writelog(4, 1, 112, 'You are not allowed to access the file', array($fileObject->getIdentifier()));
475  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
476  $this->writelog(4, 1, 111, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
477  } catch (\RuntimeException $e) {
478  $this->writelog(4, 1, 110, 'Could not delete file "%s". Write-permission problem?', array($fileObject->getIdentifier()));
479  }
480  }
481  } else {
483  if (!$this->folderHasFilesInUse($fileObject)) {
484  try {
485  $result = $fileObject->delete(true);
486  if ($result) {
487  // notify the user that the folder was deleted
489  $flashMessage = GeneralUtility::makeInstance(
490  FlashMessage::class,
491  sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.folderDeleted'), $fileObject->getName()),
492  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.folderDeleted'),
494  true
495  );
496  $this->addFlashMessage($flashMessage);
497  // Log success
498  $this->writelog(4, 0, 3, 'Directory "%s" deleted', array($fileObject->getIdentifier()));
499  }
500  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
501  $this->writelog(4, 1, 120, 'Could not delete directory! Is directory "%s" empty? (You are not allowed to delete directories recursively).', array($fileObject->getIdentifier()));
502  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
503  $this->writelog(4, 1, 123, 'You are not allowed to access the directory', array($fileObject->getIdentifier()));
504  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
505  $this->writelog(4, 1, 121, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
506  } catch (\TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException $e) {
507  $this->writelog(4, 1, 120, 'Could not delete directory "%s"! Write-permission problem?', array($fileObject->getIdentifier()));
508  }
509  }
510  }
511 
512  return $result;
513  }
514 
523  public function folderHasFilesInUse(Folder $folder)
524  {
525  $files = $folder->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, true);
526  if (empty($files)) {
527  return false;
528  }
529 
531  $fileUids = array();
532  foreach ($files as $file) {
533  $fileUids[] = $file->getUid();
534  }
535  $numberOfReferences = $this->getDatabaseConnection()->exec_SELECTcountRows(
536  '*',
537  'sys_refindex',
538  'deleted=0 AND ref_table="sys_file" AND ref_uid IN (' . implode(',', $fileUids) . ') AND tablename<>"sys_file_metadata"'
539  );
540 
541  $hasReferences = $numberOfReferences > 0;
542  if ($hasReferences) {
544  $flashMessage = GeneralUtility::makeInstance(
545  FlashMessage::class,
546  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.folderNotDeletedHasFilesWithReferences'),
547  $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.folderNotDeletedHasFilesWithReferences'),
549  true
550  );
551  $this->addFlashMessage($flashMessage);
552  }
553 
554  return $hasReferences;
555  }
556 
564  protected function transformFileReferenceToRecordReference(array $referenceRecord)
565  {
566  $fileReference = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
567  '*',
568  'sys_file_reference',
569  'uid=' . (int)$referenceRecord['recuid']
570  );
571  return array(
572  'recuid' => $fileReference['uid_foreign'],
573  'tablename' => $fileReference['tablenames'],
574  'field' => $fileReference['fieldname'],
575  'flexpointer' => '',
576  'softref_key' => '',
577  'sorting' => $fileReference['sorting_foreign']
578  );
579  }
580 
588  protected function getFileObject($identifier)
589  {
590  $object = $this->fileFactory->retrieveFileOrFolderObject($identifier);
591  if (!is_object($object)) {
592  throw new \TYPO3\CMS\Core\Resource\Exception\InvalidFileException('The item ' . $identifier . ' was not a file or directory!!', 1320122453);
593  }
594  if ($object->getStorage()->getUid() === 0) {
595  throw new \TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1375889830);
596  }
597  return $object;
598  }
599 
613  protected function func_copy($cmds)
614  {
615  if (!$this->isInit) {
616  return false;
617  }
618  $sourceFileObject = $this->getFileObject($cmds['data']);
620  $targetFolderObject = $this->getFileObject($cmds['target']);
621  // Basic check
622  if (!$targetFolderObject instanceof Folder) {
623  $this->writelog(2, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
624  return false;
625  }
626  // If this is TRUE, we append _XX to the file name if
627  $appendSuffixOnConflict = (string)$cmds['altName'];
628  $resultObject = null;
629  $conflictMode = $appendSuffixOnConflict !== '' ? DuplicationBehavior::RENAME : DuplicationBehavior::CANCEL;
630  // Copying the file
631  if ($sourceFileObject instanceof File) {
632  try {
633  $resultObject = $sourceFileObject->copyTo($targetFolderObject, null, $conflictMode);
634  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
635  $this->writelog(2, 1, 114, 'You are not allowed to copy files', '');
636  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
637  $this->writelog(2, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
638  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
639  $this->writelog(2, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
640  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
641  $this->writelog(2, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
642  } catch (\BadMethodCallException $e) {
643  $this->writelog(3, 1, 128, 'The function to copy a file between storages is not yet implemented', array());
644  } catch (\RuntimeException $e) {
645  $this->writelog(2, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
646  }
647  if ($resultObject) {
648  $this->writelog(2, 0, 1, 'File "%s" copied to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
649  }
650  } else {
651  // Else means this is a Folder
652  $sourceFolderObject = $sourceFileObject;
653  try {
654  $resultObject = $sourceFolderObject->copyTo($targetFolderObject, null, $conflictMode);
655  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
656  $this->writelog(2, 1, 125, 'You are not allowed to copy directories', '');
657  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
658  $this->writelog(2, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
659  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
660  $this->writelog(2, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
661  } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException $e) {
662  $this->writelog(2, 1, 122, 'Cannot copy folder "%s" into target folder "%s", because the target folder is already within the folder to be copied!', array($sourceFolderObject->getName(), $targetFolderObject->getName()));
663  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
664  $this->writelog(2, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
665  } catch (\BadMethodCallException $e) {
666  $this->writelog(3, 1, 129, 'The function to copy a folder between storages is not yet implemented', array());
667  } catch (\RuntimeException $e) {
668  $this->writelog(2, 2, 119, 'Directory "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
669  }
670  if ($resultObject) {
671  $this->writelog(2, 0, 2, 'Directory "%s" copied to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
672  }
673  }
674  return $resultObject;
675  }
676 
690  protected function func_move($cmds)
691  {
692  if (!$this->isInit) {
693  return false;
694  }
695  $sourceFileObject = $this->getFileObject($cmds['data']);
696  $targetFolderObject = $this->getFileObject($cmds['target']);
697  // Basic check
698  if (!$targetFolderObject instanceof Folder) {
699  $this->writelog(3, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
700  return false;
701  }
702  $alternativeName = (string)$cmds['altName'];
703  $resultObject = null;
704  // Moving the file
705  if ($sourceFileObject instanceof File) {
706  try {
707  if ($alternativeName !== '') {
708  // Don't allow overwriting existing files, but find a new name
709  $resultObject = $sourceFileObject->moveTo($targetFolderObject, $alternativeName, DuplicationBehavior::RENAME);
710  } else {
711  // Don't allow overwriting existing files
712  $resultObject = $sourceFileObject->moveTo($targetFolderObject, null, DuplicationBehavior::CANCEL);
713  }
714  $this->writelog(3, 0, 1, 'File "%s" moved to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
715  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
716  $this->writelog(3, 1, 114, 'You are not allowed to move files', '');
717  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
718  $this->writelog(3, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
719  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
720  $this->writelog(3, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
721  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
722  $this->writelog(3, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
723  } catch (\BadMethodCallException $e) {
724  $this->writelog(3, 1, 126, 'The function to move a file between storages is not yet implemented', array());
725  } catch (\RuntimeException $e) {
726  $this->writelog(3, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
727  }
728  } else {
729  // Else means this is a Folder
730  $sourceFolderObject = $sourceFileObject;
731  try {
732  if ($alternativeName !== '') {
733  // Don't allow overwriting existing files, but find a new name
734  $resultObject = $sourceFolderObject->moveTo($targetFolderObject, $alternativeName, DuplicationBehavior::RENAME);
735  } else {
736  // Don't allow overwriting existing files
737  $resultObject = $sourceFolderObject->moveTo($targetFolderObject, null, DuplicationBehavior::RENAME);
738  }
739  $this->writelog(3, 0, 2, 'Directory "%s" moved to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
740  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
741  $this->writelog(3, 1, 125, 'You are not allowed to move directories', '');
742  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
743  $this->writelog(3, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
744  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
745  $this->writelog(3, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
746  } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException $e) {
747  $this->writelog(3, 1, 122, 'Cannot move folder "%s" into target folder "%s", because the target folder is already within the folder to be moved!', array($sourceFolderObject->getName(), $targetFolderObject->getName()));
748  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
749  $this->writelog(3, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
750  } catch (\BadMethodCallException $e) {
751  $this->writelog(3, 1, 127, 'The function to move a folder between storages is not yet implemented', array());
752  } catch (\RuntimeException $e) {
753  $this->writelog(3, 2, 119, 'Directory "%s" WAS NOT moved to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
754  }
755  }
756  return $resultObject;
757  }
758 
770  public function func_rename($cmds)
771  {
772  if (!$this->isInit) {
773  return false;
774  }
775  $sourceFileObject = $this->getFileObject($cmds['data']);
776  $sourceFile = $sourceFileObject->getName();
777  $targetFile = $cmds['target'];
778  $resultObject = null;
779  if ($sourceFileObject instanceof File) {
780  try {
781  // Try to rename the File
782  $resultObject = $sourceFileObject->rename($targetFile);
783  $this->writelog(5, 0, 1, 'File renamed from "%s" to "%s"', array($sourceFile, $targetFile));
784  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
785  $this->writelog(5, 1, 102, 'You are not allowed to rename files!', '');
786  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
787  $this->writelog(5, 1, 101, 'Extension of file name "%s" or "%s" was not allowed!', array($sourceFileObject->getName(), $targetFile));
788  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
789  $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
790  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
791  $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
792  } catch (\RuntimeException $e) {
793  $this->writelog(5, 1, 100, 'File "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
794  }
795  } else {
796  // Else means this is a Folder
797  try {
798  // Try to rename the Folder
799  $resultObject = $sourceFileObject->rename($targetFile);
800  $this->writelog(5, 0, 2, 'Directory renamed from "%s" to "%s"', array($sourceFile, $targetFile));
801  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
802  $this->writelog(5, 1, 111, 'You are not allowed to rename directories!', '');
803  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
804  $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
805  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
806  $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
807  } catch (\RuntimeException $e) {
808  $this->writelog(5, 1, 110, 'Directory "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
809  }
810  }
811  return $resultObject;
812  }
813 
824  public function func_newfolder($cmds)
825  {
826  if (!$this->isInit) {
827  return false;
828  }
829  $targetFolderObject = $this->getFileObject($cmds['target']);
830  if (!$targetFolderObject instanceof Folder) {
831  $this->writelog(6, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
832  return false;
833  }
834  $resultObject = null;
835  try {
836  $folderName = $cmds['data'];
837  $resultObject = $targetFolderObject->createFolder($folderName);
838  $this->writelog(6, 0, 1, 'Directory "%s" created in "%s"', array($folderName, $targetFolderObject->getIdentifier() . '/'));
839  } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException $e) {
840  $this->writelog(6, 1, 104, 'Invalid folder name "%s"!', [$folderName]);
841  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
842  $this->writelog(6, 1, 103, 'You are not allowed to create directories!', '');
843  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
844  $this->writelog(6, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier() . '/'));
845  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
846  $this->writelog(6, 1, 101, 'File or directory "%s" existed already!', array($folderName));
847  } catch (\RuntimeException $e) {
848  $this->writelog(6, 1, 100, 'Directory "%s" not created. Write-permission problem in "%s"?', array($folderName, $targetFolderObject->getIdentifier() . '/'));
849  }
850  return $resultObject;
851  }
852 
862  public function func_newfile($cmds)
863  {
864  if (!$this->isInit) {
865  return false;
866  }
867  $targetFolderObject = $this->getFileObject($cmds['target']);
868  if (!$targetFolderObject instanceof Folder) {
869  $this->writelog(8, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
870  return false;
871  }
872  $resultObject = null;
873  try {
874  $fileName = $cmds['data'];
875  $resultObject = $targetFolderObject->createFile($fileName);
876  $this->writelog(8, 0, 1, 'File created: "%s"', array($fileName));
877  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
878  $this->writeLog(8, 1, 106, 'Extension of file "%s" was not allowed!', array($fileName));
879  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
880  $this->writelog(8, 1, 103, 'You are not allowed to create files!', '');
881  } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
882  $this->writelog(8, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
883  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
884  $this->writelog(8, 1, 101, 'File existed already in "%s"!', array($targetFolderObject->getIdentifier()));
885  } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException $e) {
886  $this->writelog(8, 1, 106, 'File name "%s" was not allowed!', $fileName);
887  } catch (\RuntimeException $e) {
888  $this->writelog(8, 1, 100, 'File "%s" was not created! Write-permission problem in "%s"?', array($fileName, $targetFolderObject->getIdentifier()));
889  }
890  return $resultObject;
891  }
892 
899  public function func_edit($cmds)
900  {
901  if (!$this->isInit) {
902  return false;
903  }
904  // Example indentifier for $cmds['target'] => "4:mypath/tomyfolder/myfile.jpg"
905  // for backwards compatibility: the combined file identifier was the path+filename
906  $fileIdentifier = $cmds['target'];
907  $fileObject = $this->getFileObject($fileIdentifier);
908  // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
909  $content = $cmds['data'];
910  if (!$fileObject instanceof File) {
911  $this->writelog(9, 2, 123, 'Target "%s" was not a file!', array($fileIdentifier));
912  return false;
913  }
914  $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
915  if (!GeneralUtility::inList($extList, $fileObject->getExtension())) {
916  $this->writelog(9, 1, 102, 'File extension "%s" is not a textfile format! (%s)', array($fileObject->getExtension(), $extList));
917  return false;
918  }
919  try {
920  $fileObject->setContents($content);
921  clearstatcache();
922  $this->writelog(9, 0, 1, 'File saved to "%s", bytes: %s, MD5: %s ', array($fileObject->getIdentifier(), $fileObject->getSize(), md5($content)));
923  return true;
924  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
925  $this->writelog(9, 1, 104, 'You are not allowed to edit files!', '');
926  return false;
927  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileWritePermissionsException $e) {
928  $this->writelog(9, 1, 100, 'File "%s" was not saved! Write-permission problem?', array($fileObject->getIdentifier()));
929  return false;
930  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
931  $this->writelog(9, 1, 100, 'File "%s" was not saved! File extension rejected!', array($fileObject->getIdentifier()));
932  return false;
933  }
934  }
935 
964  public function func_upload($cmds)
965  {
966  if (!$this->isInit) {
967  return false;
968  }
969  $uploadPosition = $cmds['data'];
970  $uploadedFileData = $_FILES['upload_' . $uploadPosition];
971  if (empty($uploadedFileData['name']) || is_array($uploadedFileData['name']) && empty($uploadedFileData['name'][0])) {
972  $this->writelog(1, 2, 108, 'No file was uploaded!', '');
973  return false;
974  }
975  // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
976  $targetFolderObject = $this->getFileObject($cmds['target']);
977  // Uploading with non HTML-5-style, thus, make an array out of it, so we can loop over it
978  if (!is_array($uploadedFileData['name'])) {
979  $uploadedFileData = array(
980  'name' => array($uploadedFileData['name']),
981  'type' => array($uploadedFileData['type']),
982  'tmp_name' => array($uploadedFileData['tmp_name']),
983  'size' => array($uploadedFileData['size'])
984  );
985  }
986  $resultObjects = array();
987  $numberOfUploadedFilesForPosition = count($uploadedFileData['name']);
988  // Loop through all uploaded files
989  for ($i = 0; $i < $numberOfUploadedFilesForPosition; $i++) {
990  $fileInfo = array(
991  'name' => $uploadedFileData['name'][$i],
992  'type' => $uploadedFileData['type'][$i],
993  'tmp_name' => $uploadedFileData['tmp_name'][$i],
994  'size' => $uploadedFileData['size'][$i]
995  );
996  try {
997  if ((int)$this->dontCheckForUnique === 1) {
998  GeneralUtility::deprecationLog('dontCheckForUnique = 1 is deprecated. Use setExistingFilesConflictMode(DuplicationBehavior::REPLACE);. Support for dontCheckForUnique will be removed in TYPO3 CMS 8.');
999  $this->existingFilesConflictMode = DuplicationBehavior::cast(DuplicationBehavior::REPLACE);
1000  }
1001 
1003  $fileObject = $targetFolderObject->addUploadedFile($fileInfo, (string)$this->existingFilesConflictMode);
1004  $fileObject = ResourceFactory::getInstance()->getFileObjectByStorageAndIdentifier($targetFolderObject->getStorage()->getUid(), $fileObject->getIdentifier());
1005  if ($this->existingFilesConflictMode->equals(DuplicationBehavior::REPLACE)) {
1006  $this->getIndexer($fileObject->getStorage())->updateIndexEntry($fileObject);
1007  }
1008  $resultObjects[] = $fileObject;
1009  $this->internalUploadMap[$uploadPosition] = $fileObject->getCombinedIdentifier();
1010  $this->writelog(1, 0, 1, 'Uploading file "%s" to "%s"', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
1011  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileWritePermissionsException $e) {
1012  $this->writelog(1, 1, 107, 'You are not allowed to override "%s"!', array($fileInfo['name']));
1013  } catch (\TYPO3\CMS\Core\Resource\Exception\UploadException $e) {
1014  $this->writelog(1, 2, 106, 'The upload has failed, no uploaded file found!', '');
1015  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
1016  $this->writelog(1, 1, 105, 'You are not allowed to upload files!', '');
1017  } catch (\TYPO3\CMS\Core\Resource\Exception\UploadSizeException $e) {
1018  $this->writelog(1, 1, 104, 'The uploaded file "%s" exceeds the size-limit', array($fileInfo['name']));
1019  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
1020  $this->writelog(1, 1, 103, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
1021  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
1022  $this->writelog(1, 1, 102, 'Extension of file name "%s" is not allowed in "%s"!', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
1023  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
1024  $this->writelog(1, 1, 101, 'No unique filename available in "%s"!', array($targetFolderObject->getIdentifier()));
1025  } catch (\RuntimeException $e) {
1026  $this->writelog(1, 1, 100, 'Uploaded file could not be moved! Write-permission problem in "%s"?', array($targetFolderObject->getIdentifier()));
1027  }
1028  }
1029 
1030  return $resultObjects;
1031  }
1032 
1040  public function func_unzip($cmds)
1041  {
1042  if (!$this->isInit || $this->dont_use_exec_commands) {
1043  return false;
1044  }
1045  $theFile = $cmds['data'];
1046  if (!@is_file($theFile)) {
1047  $this->writelog(7, 2, 105, 'The file "%s" did not exist!', array($theFile));
1048  return false;
1049  }
1050  $fI = GeneralUtility::split_fileref($theFile);
1051  if (!isset($cmds['target'])) {
1052  $cmds['target'] = $fI['path'];
1053  }
1054  // Clean up destination directory
1055  // !!! Method has been put in the local driver, can be saftely removed
1056  $theDest = $this->is_directory($cmds['target']);
1057  if (!$theDest) {
1058  $this->writelog(7, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
1059  return false;
1060  }
1061  if (!$this->actionPerms['unzipFile']) {
1062  $this->writelog(7, 1, 103, 'You are not allowed to unzip files', '');
1063  return false;
1064  }
1065  if ($fI['fileext'] != 'zip') {
1066  $this->writelog(7, 1, 102, 'File extension is not "zip"', '');
1067  return false;
1068  }
1069  if (!$this->checkIfFullAccess($theDest)) {
1070  $this->writelog(7, 1, 101, 'You don\'t have full access to the destination directory "%s"!', array($theDest));
1071  return false;
1072  }
1073  // !!! Method has been put in the sotrage driver, can be saftely removed
1074  if ($this->checkPathAgainstMounts($theFile) && $this->checkPathAgainstMounts($theDest . '/')) {
1075  // No way to do this under windows.
1076  $cmd = $this->unzipPath . 'unzip -qq ' . escapeshellarg($theFile) . ' -d ' . escapeshellarg($theDest);
1077  CommandUtility::exec($cmd);
1078  $this->writelog(7, 0, 1, 'Unzipping file "%s" in "%s"', array($theFile, $theDest));
1079  return true;
1080  } else {
1081  $this->writelog(7, 1, 100, 'File "%s" or destination "%s" was not within your mountpoints!', array($theFile, $theDest));
1082  return false;
1083  }
1084  }
1085 
1095  protected function replaceFile(array $cmdArr)
1096  {
1097  if (!$this->isInit) {
1098  return false;
1099  }
1100 
1101  $uploadPosition = $cmdArr['data'];
1102  $fileInfo = $_FILES['replace_' . $uploadPosition];
1103  if (empty($fileInfo['name'])) {
1104  $this->writelog(1, 2, 108, 'No file was uploaded for replacing!', '');
1105  return false;
1106  }
1107 
1108  $keepFileName = ($cmdArr['keepFilename'] == 1) ? true : false;
1109  $resultObjects = array();
1110 
1111  try {
1112  $fileObjectToReplace = $this->getFileObject($cmdArr['uid']);
1113  $folder = $fileObjectToReplace->getParentFolder();
1114  $resourceStorage = $fileObjectToReplace->getStorage();
1115 
1116  $fileObject = $resourceStorage->addUploadedFile($fileInfo, $folder, $fileObjectToReplace->getName(), DuplicationBehavior::REPLACE);
1117 
1118  // Check if there is a file that is going to be uploaded that has a different name as the replacing one
1119  // but exists in that folder as well.
1120  // rename to another name, but check if the name is already given
1121  if ($keepFileName === false) {
1122  // if a file with the same name already exists, we need to change it to _01 etc.
1123  // if the file does not exist, we can do a simple rename
1124  $resourceStorage->moveFile($fileObject, $folder, $fileInfo['name'], DuplicationBehavior::RENAME);
1125  }
1126 
1127  $resultObjects[] = $fileObject;
1128  $this->internalUploadMap[$uploadPosition] = $fileObject->getCombinedIdentifier();
1129 
1130  $this->writelog(1, 0, 1, 'Replacing file "%s" to "%s"', array($fileInfo['name'], $fileObjectToReplace->getIdentifier()));
1131  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileWritePermissionsException $e) {
1132  $this->writelog(1, 1, 107, 'You are not allowed to override "%s"!', array($fileInfo['name']));
1133  } catch (\TYPO3\CMS\Core\Resource\Exception\UploadException $e) {
1134  $this->writelog(1, 2, 106, 'The upload has failed, no uploaded file found!', '');
1135  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
1136  $this->writelog(1, 1, 105, 'You are not allowed to upload files!', '');
1137  } catch (\TYPO3\CMS\Core\Resource\Exception\UploadSizeException $e) {
1138  $this->writelog(1, 1, 104, 'The uploaded file "%s" exceeds the size-limit', array($fileInfo['name']));
1139  } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
1140  $this->writelog(1, 1, 103, 'Destination path "%s" was not within your mountpoints!', array($fileObjectToReplace->getIdentifier()));
1141  } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
1142  $this->writelog(1, 1, 102, 'Extension of file name "%s" is not allowed in "%s"!', array($fileInfo['name'], $fileObjectToReplace->getIdentifier()));
1143  } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
1144  $this->writelog(1, 1, 101, 'No unique filename available in "%s"!', array($fileObjectToReplace->getIdentifier()));
1145  } catch (\RuntimeException $e) {
1146  throw $e;
1147  }
1148  return $resultObjects;
1149  }
1150 
1157  protected function addFlashMessage(FlashMessage $flashMessage)
1158  {
1160  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1161 
1163  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1164  $defaultFlashMessageQueue->enqueue($flashMessage);
1165  }
1166 
1173  protected function getIndexer(ResourceStorage $storage)
1174  {
1175  return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Index\Indexer::class, $storage);
1176  }
1177 
1183  protected function getDatabaseConnection()
1184  {
1185  return $GLOBALS['TYPO3_DB'];
1186  }
1187 
1191  protected function getBackendUser()
1192  {
1193  return $GLOBALS['BE_USER'];
1194  }
1195 }