6de0d17862413682e9a671a8687b69d7b2771af6
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Utility / File / ExtendedFileUtility.php
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
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Core\Messaging\FlashMessageService;
21 use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
22 use TYPO3\CMS\Core\Resource\File;
23 use TYPO3\CMS\Core\Resource\Folder;
24 use TYPO3\CMS\Core\Resource\ResourceFactory;
25 use TYPO3\CMS\Core\Resource\ResourceStorage;
26 use TYPO3\CMS\Core\Utility\CommandUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\PathUtility;
29
30 /**
31 * Contains functions for performing file operations like copying, pasting, uploading, moving,
32 * deleting etc. through the TCE
33 *
34 * See document "TYPO3 Core API" for syntax
35 *
36 * This class contains functions primarily used by tce_file.php (TYPO3 Core Engine for file manipulation)
37 * Functions include copying, moving, deleting, uploading and so on...
38 *
39 * Important internal variables:
40 *
41 * $filemounts (see basicFileFunctions)
42 * $f_ext (see basicFileFunctions)
43 *
44 * All fileoperations must be within the filemount-paths. Further the fileextension
45 * MUST validate TRUE with the f_ext array
46 *
47 * The unzip-function allows unzip only if the destination path has it's f_ext[]['allow'] set to '*'!!
48 * You are allowed to copy/move folders within the same 'space' (web/ftp).
49 * You are allowed to copy/move folders between spaces (web/ftp) IF the destination has it's f_ext[]['allow'] set to '*'!
50 *
51 * Advice:
52 * You should always exclude php-files from the webspace. This will keep people from uploading, copy/moving and renaming files to become executable php scripts.
53 * You should never mount a ftp_space 'below' the webspace so that it reaches into the webspace. This is because if somebody unzips a zip-file in the ftp-space so that it reaches out into the webspace this will be a violation of the safety
54 * For example this is a bad idea: you have an ftp-space that is '/www/' and a web-space that is '/www/htdocs/'
55 *
56 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
57 */
58 class ExtendedFileUtility extends BasicFileUtility {
59
60 /**
61 * External static variables:
62 * Notice; some of these are overridden in the start() method with values from $GLOBALS['TYPO3_CONF_VARS']['BE']
63 * Path to unzip-program (with trailing '/')
64 *
65 * @var string
66 */
67 public $unzipPath = '';
68
69 /**
70 * If set, the uploaded files will overwrite existing files.
71 *
72 * @var bool
73 */
74 public $dontCheckForUnique = 0;
75
76 /**
77 * This array is self-explaining (look in the class below).
78 * It grants access to the functions. This could be set from outside in order to enabled functions to users.
79 * See also the function setActionPermissions() which takes input directly from the user-record
80 *
81 * @var array
82 */
83 public $actionPerms = array(
84 // File permissions
85 'addFile' => FALSE,
86 'readFile' => FALSE,
87 'writeFile' => FALSE,
88 'copyFile' => FALSE,
89 'moveFile' => FALSE,
90 'renameFile' => FALSE,
91 'unzipFile' => FALSE,
92 'deleteFile' => FALSE,
93 // Folder permissions
94 'addFolder' => FALSE,
95 'readFolder' => FALSE,
96 'writeFolder' => FALSE,
97 'copyFolder' => FALSE,
98 'moveFolder' => FALSE,
99 'renameFolder' => FALSE,
100 'deleteFolder' => FALSE,
101 'recursivedeleteFolder' => FALSE
102 );
103
104 /**
105 * This is regarded to be the recycler folder
106 *
107 * @var string
108 */
109 public $recyclerFN = '_recycler_';
110
111 /**
112 * Will contain map between upload ID and the final filename
113 *
114 * @var array
115 */
116 public $internalUploadMap = array();
117
118 /**
119 * @var string
120 */
121 public $lastError = '';
122
123 /**
124 * All error messages from the file operations of this script instance
125 *
126 * @var array
127 */
128 protected $errorMessages = array();
129
130 /**
131 * @var array
132 */
133 protected $fileCmdMap;
134
135 /**
136 * The File Factory
137 *
138 * @var \TYPO3\CMS\Core\Resource\ResourceFactory
139 */
140 protected $fileFactory;
141
142 /**
143 * Initialization of the class
144 *
145 * @param array $fileCmds Array with the commands to execute. See "TYPO3 Core API" document
146 * @return void
147 */
148 public function start($fileCmds) {
149 $unzipPath = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path']);
150 if (substr($unzipPath, -1) !== '/' && is_dir($unzipPath)) {
151 // Make sure the path ends with a slash
152 $unzipPath .= '/';
153 }
154 $this->unzipPath = $unzipPath;
155 // Initialize Object Factory
156 $this->fileFactory = ResourceFactory::getInstance();
157 // Initializing file processing commands:
158 $this->fileCmdMap = $fileCmds;
159 }
160
161 /**
162 * Sets the file action permissions.
163 * If no argument is given, permissions of the currently logged in backend user are taken into account.
164 *
165 * @param array $permissions File Permissions.
166 */
167 public function setActionPermissions(array $permissions = array()) {
168 if (empty($permissions)) {
169 $permissions = $GLOBALS['BE_USER']->getFilePermissions();
170 }
171 $this->actionPerms = $permissions;
172 }
173
174 /**
175 * Processing the command array in $this->fileCmdMap
176 *
177 * @return mixed FALSE, if the file functions were not initialized
178 * @throws \UnexpectedValueException
179 */
180 public function processData() {
181 $result = array();
182 if (!$this->isInit) {
183 return FALSE;
184 }
185 if (is_array($this->fileCmdMap)) {
186 // Check if there were uploads expected, but no one made
187 if ($this->fileCmdMap['upload']) {
188 $uploads = $this->fileCmdMap['upload'];
189 foreach ($uploads as $upload) {
190 if (empty($_FILES[('upload_' . $upload['data'])]['name'])
191 || (is_array($_FILES[('upload_' . $upload['data'])]['name'])
192 && empty($_FILES[('upload_' . $upload['data'])]['name'][0])
193 )
194 ) {
195 unset($this->fileCmdMap['upload'][$upload['data']]);
196 }
197 }
198 if (count($this->fileCmdMap['upload']) == 0) {
199 $this->writelog(1, 1, 108, 'No file was uploaded!', '');
200 }
201 }
202
203 // Check if there were new folder names expected, but non given
204 if ($this->fileCmdMap['newfolder']) {
205 foreach ($this->fileCmdMap['newfolder'] as $key => $cmdArr) {
206 if (empty($cmdArr['data'])) {
207 unset($this->fileCmdMap['newfolder'][$key]);
208 }
209 }
210 if (count($this->fileCmdMap['newfolder']) === 0) {
211 $this->writeLog(6, 1, 108, 'No name for new folder given!', '');
212 }
213 }
214
215 // Traverse each set of actions
216 foreach ($this->fileCmdMap as $action => $actionData) {
217 // Traverse all action data. More than one file might be affected at the same time.
218 if (is_array($actionData)) {
219 $result[$action] = array();
220 foreach ($actionData as $cmdArr) {
221 // Clear file stats
222 clearstatcache();
223 // Branch out based on command:
224 switch ($action) {
225 case 'delete':
226 $result[$action][] = $this->func_delete($cmdArr);
227 break;
228 case 'copy':
229 $result[$action][] = $this->func_copy($cmdArr);
230 break;
231 case 'move':
232 $result[$action][] = $this->func_move($cmdArr);
233 break;
234 case 'rename':
235 $result[$action][] = $this->func_rename($cmdArr);
236 break;
237 case 'newfolder':
238 $result[$action][] = $this->func_newfolder($cmdArr);
239 break;
240 case 'newfile':
241 $result[$action][] = $this->func_newfile($cmdArr);
242 break;
243 case 'editfile':
244 $result[$action][] = $this->func_edit($cmdArr);
245 break;
246 case 'upload':
247 $result[$action][] = $this->func_upload($cmdArr);
248 break;
249 case 'unzip':
250 $result[$action][] = $this->func_unzip($cmdArr);
251 break;
252 }
253 // Hook for post-processing the action
254 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_extfilefunc.php']['processData'])) {
255 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_extfilefunc.php']['processData'] as $classRef) {
256 $hookObject = GeneralUtility::getUserObj($classRef);
257 if (!$hookObject instanceof ExtendedFileUtilityProcessDataHookInterface) {
258 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Core\\Utility\\File\\ExtendedFileUtilityProcessDataHookInterface', 1279719168);
259 }
260 $hookObject->processData_postProcessAction($action, $cmdArr, $result[$action], $this);
261 }
262 }
263 }
264 }
265 }
266 }
267 return $result;
268 }
269
270 /**
271 * Adds all log error messages from the operations of this script instance to the FlashMessageQueue
272 *
273 * @return void
274 */
275 public function pushErrorMessagesToFlashMessageQueue() {
276 foreach ($this->getErrorMessages() as $msg) {
277 $flashMessage = GeneralUtility::makeInstance(
278 FlashMessage::class,
279 $msg,
280 '',
281 FlashMessage::ERROR,
282 TRUE
283 );
284 $this->addFlashMessage($flashMessage);
285 }
286 }
287
288 /**
289 * Return all error messages from the file operations of this script instance
290 *
291 * @return array all errorMessages as a numerical array
292 */
293 public function getErrorMessages() {
294 return $this->errorMessages;
295 }
296
297 /**
298 * @param int $action The action number. See the functions in the class for a hint. Eg. edit is '9', upload is '1' ...
299 * @param int $error The severity: 0 = message, 1 = error, 2 = System Error, 3 = security notice (admin)
300 * @param int $details_nr This number is unique for every combination of $type and $action. This is the error-message number, which can later be used to translate error messages.
301 * @param string $details This is the default, raw error message in english
302 * @param array $data Array with special information that may go into $details by "%s" marks / sprintf() when the log is shown
303 * @return void
304 */
305 public function writeLog($action, $error, $details_nr, $details, $data) {
306 // Type value for tce_file.php
307 $type = 2;
308 if (is_object($this->getBackendUser())) {
309 $this->getBackendUser()->writelog($type, $action, $error, $details_nr, $details, $data);
310 }
311 if ($error > 0) {
312 $this->lastError = vsprintf($details, $data);
313 $this->errorMessages[] = $this->lastError;
314 }
315 }
316
317 /*************************************
318 *
319 * File operation functions
320 *
321 **************************************/
322 /**
323 * Deleting files and folders (action=4)
324 *
325 * @param array $cmds $cmds['data'] is the file/folder to delete
326 * @return bool Returns TRUE upon success
327 */
328 public function func_delete($cmds) {
329 $result = FALSE;
330 if (!$this->isInit) {
331 return $result;
332 }
333 // Example indentifier for $cmds['data'] => "4:mypath/tomyfolder/myfile.jpg"
334 // for backwards compatibility: the combined file identifier was the path+filename
335 try {
336 $fileObject = $this->getFileObject($cmds['data']);
337 } catch (ResourceDoesNotExistException $ex) {
338 $flashMessage = GeneralUtility::makeInstance(
339 FlashMessage::class,
340 sprintf( $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileNotFound'), $cmds['data']),
341 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileNotFound'),
342 FlashMessage::ERROR,
343 TRUE
344 );
345 $this->addFlashMessage($flashMessage);
346
347 return FALSE;
348 }
349 // @todo implement the recycler feature which has been removed from the original implementation
350 // checks to delete the file
351 if ($fileObject instanceof File) {
352 // check if the file still has references
353 // Exclude sys_file_metadata records as these are no use references
354 $refIndexRecords = $this->getDatabaseConnection()->exec_SELECTgetRows(
355 '*',
356 'sys_refindex',
357 'deleted=0 AND ref_table="sys_file" AND ref_uid=' . (int)$fileObject->getUid()
358 . ' AND tablename != "sys_file_metadata"'
359 );
360 $deleteFile = TRUE;
361 if (count($refIndexRecords) > 0) {
362 $shortcutContent = array();
363 $brokenReferences = array();
364
365 foreach ($refIndexRecords as $fileReferenceRow) {
366 if ($fileReferenceRow['tablename'] === 'sys_file_reference') {
367 $row = $this->transformFileReferenceToRecordReference($fileReferenceRow);
368 $shortcutRecord = BackendUtility::getRecord($row['tablename'], $row['recuid']);
369
370 if ($shortcutRecord) {
371 $icon = IconUtility::getSpriteIconForRecord($row['tablename'], $shortcutRecord);
372 $tagParameters = array(
373 'class' => 't3-js-clickmenutrigger',
374 'data-table' => $row['tablename'],
375 'data-uid' => $row['recuid'],
376 'data-listframe' => 1,
377 'data-iteminfo' => '%2Binfo,history,edit'
378 );
379 $icon = '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $icon . '</a>';
380 $shortcutContent[] = $icon . htmlspecialchars((BackendUtility::getRecordTitle($row['tablename'], $shortcutRecord) . ' [' . BackendUtility::getRecordPath($shortcutRecord['pid'], '', 80) . ']'));
381 } else {
382 $brokenReferences[] = $fileReferenceRow['ref_uid'];
383 }
384 }
385 }
386 if (!empty($brokenReferences)) {
387 // render a message that the file has broken references
388 $flashMessage = GeneralUtility::makeInstance(
389 FlashMessage::class,
390 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileHasBrokenReferences'), count($brokenReferences)),
391 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileHasBrokenReferences'),
392 FlashMessage::INFO,
393 TRUE
394 );
395 $this->addFlashMessage($flashMessage);
396 }
397 if (!empty($shortcutContent)) {
398 // render a message that the file could not be deleted
399 $flashMessage = GeneralUtility::makeInstance(
400 FlashMessage::class,
401 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileNotDeletedHasReferences'), $fileObject->getName()) . '<br />' . implode('<br />', $shortcutContent),
402 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileNotDeletedHasReferences'),
403 FlashMessage::WARNING,
404 TRUE
405 );
406 $this->addFlashMessage($flashMessage);
407 $deleteFile = FALSE;
408 }
409 }
410
411 if ($deleteFile) {
412 try {
413 $result = $fileObject->delete();
414
415 // show the user that the file was deleted
416 $flashMessage = GeneralUtility::makeInstance(
417 FlashMessage::class,
418 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.fileDeleted'), $fileObject->getName()),
419 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.fileDeleted'),
420 FlashMessage::OK,
421 TRUE
422 );
423 $this->addFlashMessage($flashMessage);
424 // Log success
425 $this->writelog(4, 0, 1, 'File "%s" deleted', array($fileObject->getIdentifier()));
426 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
427 $this->writelog(4, 1, 112, 'You are not allowed to access the file', array($fileObject->getIdentifier()));
428 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
429 $this->writelog(4, 1, 111, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
430 } catch (\RuntimeException $e) {
431 $this->writelog(4, 1, 110, 'Could not delete file "%s". Write-permission problem?', array($fileObject->getIdentifier()));
432 }
433 }
434 } else {
435 try {
436 /** @var \TYPO3\CMS\Core\Resource\Folder $fileObject */
437 $result = $fileObject->delete(TRUE);
438 if ($result) {
439 // notify the user that the folder was deleted
440 /** @var FlashMessage $flashMessage */
441 $flashMessage = GeneralUtility::makeInstance(
442 FlashMessage::class,
443 sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.description.folderDeleted'), $fileObject->getName()),
444 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:message.header.folderDeleted'),
445 FlashMessage::OK,
446 TRUE
447 );
448 $this->addFlashMessage($flashMessage);
449 // Log success
450 $this->writelog(4, 0, 3, 'Directory "%s" deleted', array($fileObject->getIdentifier()));
451 }
452 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
453 $this->writelog(4, 1, 120, 'Could not delete directory! Is directory "%s" empty? (You are not allowed to delete directories recursively).', array($fileObject->getIdentifier()));
454 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
455 $this->writelog(4, 1, 123, 'You are not allowed to access the directory', array($fileObject->getIdentifier()));
456 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
457 $this->writelog(4, 1, 121, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
458 } catch (\TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException $e) {
459 $this->writelog(4, 1, 120, 'Could not delete directory "%s"! Write-permission problem?', array($fileObject->getIdentifier()));
460 }
461 }
462 return $result;
463 }
464
465 /**
466 * Maps results from the fal file reference table on the
467 * structure of the normal reference index table.
468 *
469 * @param array $referenceRecord
470 * @return array
471 */
472 protected function transformFileReferenceToRecordReference(array $referenceRecord) {
473 $fileReference = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
474 '*',
475 'sys_file_reference',
476 'uid=' . (int)$referenceRecord['recuid']
477 );
478 return array(
479 'recuid' => $fileReference['uid_foreign'],
480 'tablename' => $fileReference['tablenames'],
481 'field' => $fileReference['fieldname'],
482 'flexpointer' => '',
483 'softref_key' => '',
484 'sorting' => $fileReference['sorting_foreign']
485 );
486 }
487
488 /**
489 * Gets a File or a Folder object from an identifier [storage]:[fileId]
490 *
491 * @param string $identifier
492 * @return \TYPO3\CMS\Core\Resource\Folder|\TYPO3\CMS\Core\Resource\File
493 * @throws \TYPO3\CMS\Core\Resource\Exception\InvalidFileException
494 */
495 protected function getFileObject($identifier) {
496 $object = $this->fileFactory->retrieveFileOrFolderObject($identifier);
497 if (!is_object($object)) {
498 throw new \TYPO3\CMS\Core\Resource\Exception\InvalidFileException('The item ' . $identifier . ' was not a file or directory!!', 1320122453);
499 }
500 if ($object->getStorage()->getUid() === 0) {
501 throw new \TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1375889830);
502 }
503 return $object;
504 }
505
506 /**
507 * Copying files and folders (action=2)
508 *
509 * $cmds['data'] (string): The file/folder to copy
510 * + example "4:mypath/tomyfolder/myfile.jpg")
511 * + for backwards compatibility: the identifier was the path+filename
512 * $cmds['target'] (string): The path where to copy to.
513 * + example "2:targetpath/targetfolder/"
514 * $cmds['altName'] (string): Use an alternative name if the target already exists
515 *
516 * @param array $cmds Command details as described above
517 * @return \TYPO3\CMS\Core\Resource\File
518 */
519 protected function func_copy($cmds) {
520 if (!$this->isInit) {
521 return FALSE;
522 }
523 $sourceFileObject = $this->getFileObject($cmds['data']);
524 /** @var $targetFolderObject \TYPO3\CMS\Core\Resource\Folder */
525 $targetFolderObject = $this->getFileObject($cmds['target']);
526 // Basic check
527 if (!$targetFolderObject instanceof Folder) {
528 $this->writelog(2, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
529 return FALSE;
530 }
531 // If this is TRUE, we append _XX to the file name if
532 $appendSuffixOnConflict = (string)$cmds['altName'];
533 $resultObject = NULL;
534 // Copying the file
535 if ($sourceFileObject instanceof File) {
536 try {
537 $conflictMode = $appendSuffixOnConflict !== '' ? 'renameNewFile' : 'cancel';
538 $resultObject = $sourceFileObject->copyTo($targetFolderObject, NULL, $conflictMode);
539 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
540 $this->writelog(2, 1, 114, 'You are not allowed to copy files', '');
541 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
542 $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()));
543 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
544 $this->writelog(2, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
545 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
546 $this->writelog(2, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
547 } catch (\BadMethodCallException $e) {
548 $this->writelog(3, 1, 128, 'The function to copy a file between storages is not yet implemented', array());
549 } catch (\RuntimeException $e) {
550 $this->writelog(2, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
551 }
552 if ($resultObject) {
553 $this->writelog(2, 0, 1, 'File "%s" copied to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
554 }
555 } else {
556 // Else means this is a Folder
557 $sourceFolderObject = $sourceFileObject;
558 try {
559 $conflictMode = $appendSuffixOnConflict !== '' ? 'renameNewFile' : 'cancel';
560 $resultObject = $sourceFolderObject->copyTo($targetFolderObject, NULL, $conflictMode);
561 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
562 $this->writelog(2, 1, 125, 'You are not allowed to copy directories', '');
563 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
564 $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()));
565 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
566 $this->writelog(2, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
567 } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException $e) {
568 $this->writelog(2, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($targetFolderObject->getIdentifier(), $sourceFolderObject->getIdentifier()));
569 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
570 $this->writelog(2, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
571 } catch (\BadMethodCallException $e) {
572 $this->writelog(3, 1, 129, 'The function to copy a folder between storages is not yet implemented', array());
573 } catch (\RuntimeException $e) {
574 $this->writelog(2, 2, 119, 'Directory "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
575 }
576 if ($resultObject) {
577 $this->writelog(2, 0, 2, 'Directory "%s" copied to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
578 }
579 }
580 return $resultObject;
581 }
582
583 /**
584 * Moving files and folders (action=3)
585 *
586 * $cmds['data'] (string): The file/folder to move
587 * + example "4:mypath/tomyfolder/myfile.jpg")
588 * + for backwards compatibility: the identifier was the path+filename
589 * $cmds['target'] (string): The path where to move to.
590 * + example "2:targetpath/targetfolder/"
591 * $cmds['altName'] (string): Use an alternative name if the target already exists
592 *
593 * @param array $cmds Command details as described above
594 * @return \TYPO3\CMS\Core\Resource\File
595 */
596 protected function func_move($cmds) {
597 if (!$this->isInit) {
598 return FALSE;
599 }
600 $sourceFileObject = $this->getFileObject($cmds['data']);
601 $targetFolderObject = $this->getFileObject($cmds['target']);
602 // Basic check
603 if (!$targetFolderObject instanceof Folder) {
604 $this->writelog(3, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
605 return FALSE;
606 }
607 $alternativeName = (string)$cmds['altName'];
608 $resultObject = NULL;
609 // Moving the file
610 if ($sourceFileObject instanceof File) {
611 try {
612 if ($alternativeName !== '') {
613 // Don't allow overwriting existing files, but find a new name
614 $resultObject = $sourceFileObject->moveTo($targetFolderObject, $alternativeName, 'renameNewFile');
615 } else {
616 // Don't allow overwriting existing files
617 $resultObject = $sourceFileObject->moveTo($targetFolderObject, NULL, 'cancel');
618 }
619 $this->writelog(3, 0, 1, 'File "%s" moved to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
620 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
621 $this->writelog(3, 1, 114, 'You are not allowed to move files', '');
622 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
623 $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()));
624 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
625 $this->writelog(3, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
626 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
627 $this->writelog(3, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
628 } catch (\BadMethodCallException $e) {
629 $this->writelog(3, 1, 126, 'The function to move a file between storages is not yet implemented', array());
630 } catch (\RuntimeException $e) {
631 $this->writelog(3, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
632 }
633 } else {
634 // Else means this is a Folder
635 $sourceFolderObject = $sourceFileObject;
636 try {
637 if ($alternativeName !== '') {
638 // Don't allow overwriting existing files, but find a new name
639 $resultObject = $sourceFolderObject->moveTo($targetFolderObject, $alternativeName, 'renameNewFile');
640 } else {
641 // Don't allow overwriting existing files
642 $resultObject = $sourceFolderObject->moveTo($targetFolderObject, NULL, 'renameNewFile');
643 }
644 $this->writelog(3, 0, 2, 'Directory "%s" moved to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
645 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
646 $this->writelog(3, 1, 125, 'You are not allowed to move directories', '');
647 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException $e) {
648 $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()));
649 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException $e) {
650 $this->writelog(3, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
651 } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException $e) {
652 $this->writelog(3, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($targetFolderObject->getIdentifier(), $sourceFolderObject->getIdentifier()));
653 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
654 $this->writelog(3, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
655 } catch (\BadMethodCallException $e) {
656 $this->writelog(3, 1, 127, 'The function to move a folder between storages is not yet implemented', array());
657 } catch (\RuntimeException $e) {
658 $this->writelog(3, 2, 119, 'Directory "%s" WAS NOT moved to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
659 }
660 }
661 return $resultObject;
662 }
663
664 /**
665 * Renaming files or foldes (action=5)
666 *
667 * $cmds['data'] (string): The file/folder to copy
668 * + example "4:mypath/tomyfolder/myfile.jpg")
669 * + for backwards compatibility: the identifier was the path+filename
670 * $cmds['target'] (string): New name of the file/folder
671 *
672 * @param array $cmds Command details as described above
673 * @return \TYPO3\CMS\Core\Resource\File Returns the new file upon success
674 */
675 public function func_rename($cmds) {
676 if (!$this->isInit) {
677 return FALSE;
678 }
679 $sourceFileObject = $this->getFileObject($cmds['data']);
680 $targetFile = $cmds['target'];
681 $resultObject = NULL;
682 if ($sourceFileObject instanceof File) {
683 try {
684 // Try to rename the File
685 $resultObject = $sourceFileObject->rename($targetFile);
686 $this->writelog(5, 0, 1, 'File renamed from "%s" to "%s"', array($sourceFileObject->getName(), $targetFile));
687 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
688 $this->writelog(5, 1, 102, 'You are not allowed to rename files!', '');
689 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
690 $this->writelog(5, 1, 101, 'Extension of file name "%s" or "%s" was not allowed!', array($sourceFileObject->getName(), $targetFile));
691 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
692 $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
693 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
694 $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
695 } catch (\RuntimeException $e) {
696 $this->writelog(5, 1, 100, 'File "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
697 }
698 } else {
699 // Else means this is a Folder
700 try {
701 // Try to rename the Folder
702 $resultObject = $sourceFileObject->rename($targetFile);
703 $this->writelog(5, 0, 2, 'Directory renamed from "%s" to "%s"', array($sourceFileObject->getName(), $targetFile));
704 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
705 $this->writelog(5, 1, 111, 'You are not allowed to rename directories!', '');
706 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
707 $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
708 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
709 $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
710 } catch (\RuntimeException $e) {
711 $this->writelog(5, 1, 110, 'Directory "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
712 }
713 }
714 return $resultObject;
715 }
716
717 /**
718 * This creates a new folder. (action=6)
719 *
720 * $cmds['data'] (string): The new folder name
721 * $cmds['target'] (string): The path where to copy to.
722 * + example "2:targetpath/targetfolder/"
723 *
724 * @param array $cmds Command details as described above
725 * @return \TYPO3\CMS\Core\Resource\Folder Returns the new foldername upon success
726 */
727 public function func_newfolder($cmds) {
728 if (!$this->isInit) {
729 return FALSE;
730 }
731 $targetFolderObject = $this->getFileObject($cmds['target']);
732 if (!$targetFolderObject instanceof Folder) {
733 $this->writelog(6, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
734 return FALSE;
735 }
736 $resultObject = NULL;
737 try {
738 $folderName = $cmds['data'];
739 $resultObject = $targetFolderObject->createFolder($folderName);
740 $this->writelog(6, 0, 1, 'Directory "%s" created in "%s"', array($folderName, $targetFolderObject->getIdentifier() . '/'));
741 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
742 $this->writelog(6, 1, 103, 'You are not allowed to create directories!', '');
743 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
744 $this->writelog(6, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier() . '/'));
745 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException $e) {
746 $this->writelog(6, 1, 101, 'File or directory "%s" existed already!', array($folderName));
747 } catch (\RuntimeException $e) {
748 $this->writelog(6, 1, 100, 'Directory "%s" not created. Write-permission problem in "%s"?', array($folderName, $targetFolderObject->getIdentifier() . '/'));
749 }
750 return $resultObject;
751 }
752
753 /**
754 * This creates a new file. (action=8)
755 * $cmds['data'] (string): The new file name
756 * $cmds['target'] (string): The path where to create it.
757 * + example "2:targetpath/targetfolder/"
758 *
759 * @param array $cmds Command details as described above
760 * @return string Returns the new filename upon success
761 */
762 public function func_newfile($cmds) {
763 if (!$this->isInit) {
764 return FALSE;
765 }
766 $targetFolderObject = $this->getFileObject($cmds['target']);
767 if (!$targetFolderObject instanceof Folder) {
768 $this->writelog(8, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
769 return FALSE;
770 }
771 $resultObject = NULL;
772 try {
773 $fileName = $cmds['data'];
774 $resultObject = $targetFolderObject->createFile($fileName);
775 $this->writelog(8, 0, 1, 'File created: "%s"', array($fileName));
776 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
777 $this->writeLog(8, 1, 106, 'Extension of file "%s" was not allowed!', array($fileName));
778 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
779 $this->writelog(8, 1, 103, 'You are not allowed to create files!', '');
780 } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
781 $this->writelog(8, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
782 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
783 $this->writelog(8, 1, 101, 'File existed already in "%s"!', array($targetFolderObject->getIdentifier()));
784 } catch (\TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException $e) {
785 $this->writelog(8, 1, 106, 'File name "%s" was not allowed!', $fileName);
786 } catch (\RuntimeException $e) {
787 $this->writelog(8, 1, 100, 'File "%s" was not created! Write-permission problem in "%s"?', array($fileName, $targetFolderObject->getIdentifier()));
788 }
789 return $resultObject;
790 }
791
792 /**
793 * Editing textfiles or folders (action=9)
794 *
795 * @param array $cmds $cmds['data'] is the new content. $cmds['target'] is the target (file or dir)
796 * @return bool Returns TRUE on success
797 */
798 public function func_edit($cmds) {
799 if (!$this->isInit) {
800 return FALSE;
801 }
802 // Example indentifier for $cmds['target'] => "4:mypath/tomyfolder/myfile.jpg"
803 // for backwards compatibility: the combined file identifier was the path+filename
804 $fileIdentifier = $cmds['target'];
805 $fileObject = $this->getFileObject($fileIdentifier);
806 // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
807 $content = $cmds['data'];
808 if (!$fileObject instanceof File) {
809 $this->writelog(9, 2, 123, 'Target "%s" was not a file!', array($fileIdentifier));
810 return FALSE;
811 }
812 $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
813 if (!GeneralUtility::inList($extList, $fileObject->getExtension())) {
814 $this->writelog(9, 1, 102, 'File extension "%s" is not a textfile format! (%s)', array($fileObject->getExtension(), $extList));
815 return FALSE;
816 }
817 try {
818 $fileObject->setContents($content);
819 clearstatcache();
820 $this->writelog(9, 0, 1, 'File saved to "%s", bytes: %s, MD5: %s ', array($fileObject->getIdentifier(), $fileObject->getSize(), md5($content)));
821 return TRUE;
822 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
823 $this->writelog(9, 1, 104, 'You are not allowed to edit files!', '');
824 return FALSE;
825 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFileWritePermissionsException $e) {
826 $this->writelog(9, 1, 100, 'File "%s" was not saved! Write-permission problem?', array($fileObject->getIdentifier()));
827 return FALSE;
828 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
829 $this->writelog(9, 1, 100, 'File "%s" was not saved! File extension rejected!', array($fileObject->getIdentifier()));
830 return FALSE;
831 }
832 }
833
834 /**
835 * Upload of files (action=1)
836 * when having multiple uploads (HTML5-style), the array $_FILES looks like this:
837 * Array(
838 * [upload_1] => Array(
839 * [name] => Array(
840 * [0] => GData - Content-Elements and Media-Gallery.pdf
841 * [1] => CMS Expo 2011.txt
842 * )
843 * [type] => Array(
844 * [0] => application/pdf
845 * [1] => text/plain
846 * )
847 * [tmp_name] => Array(
848 * [0] => /Applications/MAMP/tmp/php/phpNrOB43
849 * [1] => /Applications/MAMP/tmp/php/phpD2HQAK
850 * )
851 * [size] => Array(
852 * [0] => 373079
853 * [1] => 1291
854 * )
855 * )
856 * )
857 * in HTML you'd need sth like this: <input type="file" name="upload_1[]" multiple="true" />
858 *
859 * @param array $cmds $cmds['data'] is the ID-number (points to the global var that holds the filename-ref ($_FILES['upload_' . $id]['name']) . $cmds['target'] is the target directory, $cmds['charset'] is the the character set of the file name (utf-8 is needed for JS-interaction)
860 * @return File[] | FALSE Returns an array of new file objects upon success. False otherwise
861 */
862 public function func_upload($cmds) {
863 if (!$this->isInit) {
864 return FALSE;
865 }
866 $uploadPosition = $cmds['data'];
867 $uploadedFileData = $_FILES['upload_' . $uploadPosition];
868 if (empty($uploadedFileData['name']) || is_array($uploadedFileData['name']) && empty($uploadedFileData['name'][0])) {
869 $this->writelog(1, 2, 108, 'No file was uploaded!', '');
870 return FALSE;
871 }
872 // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
873 $targetFolderObject = $this->getFileObject($cmds['target']);
874 // Uploading with non HTML-5-style, thus, make an array out of it, so we can loop over it
875 if (!is_array($uploadedFileData['name'])) {
876 $uploadedFileData = array(
877 'name' => array($uploadedFileData['name']),
878 'type' => array($uploadedFileData['type']),
879 'tmp_name' => array($uploadedFileData['tmp_name']),
880 'size' => array($uploadedFileData['size'])
881 );
882 }
883 $resultObjects = array();
884 $numberOfUploadedFilesForPosition = count($uploadedFileData['name']);
885 // Loop through all uploaded files
886 for ($i = 0; $i < $numberOfUploadedFilesForPosition; $i++) {
887 $fileInfo = array(
888 'name' => $uploadedFileData['name'][$i],
889 'type' => $uploadedFileData['type'][$i],
890 'tmp_name' => $uploadedFileData['tmp_name'][$i],
891 'size' => $uploadedFileData['size'][$i]
892 );
893 try {
894 // @todo can be improved towards conflict mode naming
895 if ($this->dontCheckForUnique) {
896 $conflictMode = 'replace';
897 } else {
898 $conflictMode = 'cancel';
899 }
900 /** @var $fileObject File */
901 $fileObject = $targetFolderObject->addUploadedFile($fileInfo, $conflictMode);
902 $fileObject = ResourceFactory::getInstance()->getFileObjectByStorageAndIdentifier($targetFolderObject->getStorage()->getUid(), $fileObject->getIdentifier());
903 if ($conflictMode === 'replace') {
904 $this->getIndexer($fileObject->getStorage())->updateIndexEntry($fileObject);
905 }
906 $resultObjects[] = $fileObject;
907 $this->internalUploadMap[$uploadPosition] = $fileObject->getCombinedIdentifier();
908 $this->writelog(1, 0, 1, 'Uploading file "%s" to "%s"', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
909 } catch (\TYPO3\CMS\Core\Resource\Exception\UploadException $e) {
910 $this->writelog(1, 2, 106, 'The upload has failed, no uploaded file found!', '');
911 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
912 $this->writelog(1, 1, 105, 'You are not allowed to upload files!', '');
913 } catch (\TYPO3\CMS\Core\Resource\Exception\UploadSizeException $e) {
914 $this->writelog(1, 1, 104, 'The uploaded file "%s" exceeds the size-limit', array($fileInfo['name']));
915 } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException $e) {
916 $this->writelog(1, 1, 103, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
917 } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
918 $this->writelog(1, 1, 102, 'Extension of file name "%s" is not allowed in "%s"!', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
919 } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
920 $this->writelog(1, 1, 101, 'No unique filename available in "%s"!', array($targetFolderObject->getIdentifier()));
921 } catch (\RuntimeException $e) {
922 $this->writelog(1, 1, 100, 'Uploaded file could not be moved! Write-permission problem in "%s"?', array($targetFolderObject->getIdentifier()));
923 }
924 }
925
926 return $resultObjects;
927 }
928
929 /**
930 * Unzipping file (action=7)
931 * This is permitted only if the user has fullAccess or if the file resides
932 *
933 * @param array $cmds $cmds['data'] is the zip-file. $cmds['target'] is the target directory. If not set we'll default to the same directory as the file is in.
934 * @return bool Returns TRUE on success
935 */
936 public function func_unzip($cmds) {
937 if (!$this->isInit || $this->dont_use_exec_commands) {
938 return FALSE;
939 }
940 $theFile = $cmds['data'];
941 if (!@is_file($theFile)) {
942 $this->writelog(7, 2, 105, 'The file "%s" did not exist!', array($theFile));
943 return FALSE;
944 }
945 $fI = GeneralUtility::split_fileref($theFile);
946 if (!isset($cmds['target'])) {
947 $cmds['target'] = $fI['path'];
948 }
949 // Clean up destination directory
950 // !!! Method has been put in the local driver, can be saftely removed
951 $theDest = $this->is_directory($cmds['target']);
952 if (!$theDest) {
953 $this->writelog(7, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
954 return FALSE;
955 }
956 if (!$this->actionPerms['unzipFile']) {
957 $this->writelog(7, 1, 103, 'You are not allowed to unzip files', '');
958 return FALSE;
959 }
960 if ($fI['fileext'] != 'zip') {
961 $this->writelog(7, 1, 102, 'File extension is not "zip"', '');
962 return FALSE;
963 }
964 if (!$this->checkIfFullAccess($theDest)) {
965 $this->writelog(7, 1, 101, 'You don\'t have full access to the destination directory "%s"!', array($theDest));
966 return FALSE;
967 }
968 // !!! Method has been put in the sotrage driver, can be saftely removed
969 if ($this->checkPathAgainstMounts($theFile) && $this->checkPathAgainstMounts($theDest . '/')) {
970 // No way to do this under windows.
971 $cmd = $this->unzipPath . 'unzip -qq ' . escapeshellarg($theFile) . ' -d ' . escapeshellarg($theDest);
972 CommandUtility::exec($cmd);
973 $this->writelog(7, 0, 1, 'Unzipping file "%s" in "%s"', array($theFile, $theDest));
974 return TRUE;
975 } else {
976 $this->writelog(7, 1, 100, 'File "%s" or destination "%s" was not within your mountpoints!', array($theFile, $theDest));
977 return FALSE;
978 }
979 }
980
981 /**
982 * Add flash message to message queue
983 *
984 * @param FlashMessage $flashMessage
985 * @return void
986 */
987 protected function addFlashMessage(FlashMessage $flashMessage) {
988 /** @var $flashMessageService FlashMessageService */
989 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
990
991 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
992 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
993 $defaultFlashMessageQueue->enqueue($flashMessage);
994 }
995
996 /**
997 * Gets Indexer
998 *
999 * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storage
1000 * @return \TYPO3\CMS\Core\Resource\Index\Indexer
1001 */
1002 protected function getIndexer(ResourceStorage $storage) {
1003 return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Index\Indexer::class, $storage);
1004 }
1005
1006 /**
1007 * Get database connection
1008 *
1009 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
1010 */
1011 protected function getDatabaseConnection() {
1012 return $GLOBALS['TYPO3_DB'];
1013 }
1014
1015 /**
1016 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1017 */
1018 protected function getBackendUser() {
1019 return $GLOBALS['BE_USER'];
1020 }
1021
1022 }