103aa6018f39f0e9c5ba75aea090913c8444565e
[Packages/TYPO3.CMS.git] / t3lib / file / Storage.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28
29 /**
30 * A "mount point" inside the TYPO3 file handling.
31 *
32 * A "storage" object handles
33 * - abstraction to the driver
34 * - permissions (from the driver, and from the user, + capabilities)
35 * - an entry point for files, folders, and for most other operations
36 *
37 * == Driver entry point
38 * The driver itself, that does the actual work on the file system,
39 * is inside the storage but completely shadowed by
40 * the storage, as the storage also handles the abstraction to the
41 * driver
42 *
43 * The storage can be on the local system, but can also be on a remote
44 * system. The combination of driver + configurable capabilities (storage
45 * is read-only e.g.) allows for flexible uses.
46 *
47 *
48 * == Permission system
49 * As all requests have to run through the storage, the storage knows about the
50 * permissions of a BE/FE user, the file permissions / limitations of the driver
51 * and has some configurable capabilities.
52 * Additionally, a BE user can use "filemounts" (known from previous installations)
53 * to limit his/her work-zone to only a subset (identifier and its subfolders/subfolders)
54 * of the user itself.
55 *
56 * Check 1: "User Permissions" [is the user allowed to write a file) [is the user allowed to write a file]
57 * Check 2: "File Mounts" of the User (act as subsets / filters to the identifiers) [is the user allowed to do something in this folder?]
58 * Check 3: "Capabilities" of Storage (then: of Driver) [is the storage/driver writable?]
59 * Check 4: "File permissions" of the Driver [is the folder writable?]
60 *
61 *
62 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
63 * @author Ingmar Schlecht <ingmar@typo3.org>
64 * @package TYPO3
65 * @subpackage t3lib
66 */
67 class t3lib_file_Storage {
68
69 const SIGNAL_PreProcessConfiguration = 'preProcessConfiguration';
70 const SIGNAL_PostProcessConfiguration = 'postProcessConfiguration';
71 const SIGNAL_PreFileCopy = 'preFileCopy';
72 const SIGNAL_PostFileCopy = 'postFileCopy';
73 const SIGNAL_PreFileMove = 'preFileMove';
74 const SIGNAL_PostFileMove = 'postFileMove';
75 const SIGNAL_PreFileDelete = 'preFileDelete';
76 const SIGNAL_PostFileDelete = 'postFileDelete';
77 const SIGNAL_PreFileRename = 'preFileRename';
78 const SIGNAL_PostFileRename = 'postFileRename';
79 const SIGNAL_PreFileReplace = 'preFileReplace';
80 const SIGNAL_PostFileReplace = 'postFileReplace';
81 const SIGNAL_PreFolderCopy = 'preFolderCopy';
82 const SIGNAL_PostFolderCopy = 'postFolderCopy';
83 const SIGNAL_PreFolderMove = 'preFolderMove';
84 const SIGNAL_PostFolderMove = 'postFolderMove';
85 const SIGNAL_PreFolderDelete = 'preFolderDelete';
86 const SIGNAL_PostFolderDelete = 'postFolderDelete';
87 const SIGNAL_PreFolderRename = 'preFolderRename';
88 const SIGNAL_PostFolderRename = 'postFolderRename';
89 const SIGNAL_PreFileProcess = 'preFileProcess';
90 const SIGNAL_PostFileProcess = 'postFileProcess';
91
92 /**
93 * The storage driver instance belonging to this storage.
94 *
95 * @var t3lib_file_Driver_AbstractDriver
96 */
97 protected $driver;
98
99 /**
100 * The database record for this storage
101 *
102 * @var array
103 */
104 protected $storageRecord;
105
106 /**
107 * The configuration belonging to this storage (decoded from the configuration field).
108 *
109 * @var array
110 */
111 protected $configuration;
112
113 /**
114 * The base URI to this storage.
115 *
116 * @var string
117 */
118 protected $baseUri;
119
120 /**
121 * @var t3lib_file_Service_FileProcessingService
122 */
123 protected $fileProcessingService;
124
125 /**
126 * User filemounts, added as an array, and used as filters
127 *
128 * @var array
129 */
130 protected $fileMounts = array();
131
132 /**
133 * The file permissions of the user (and their group) merged together and
134 * available as an array
135 *
136 * @var array
137 */
138 protected $userPermissions = array();
139
140 /**
141 * The capabilities of this storage as defined in the storage record.
142 * Also see the CAPABILITY_* constants below
143 *
144 * @var integer
145 */
146 protected $capabilities;
147
148 /**
149 * @var Tx_Extbase_SignalSlot_Dispatcher
150 */
151 protected $signalSlotDispatcher;
152
153 /**
154 * Capability for being browsable by (backend) users
155 */
156 const CAPABILITY_BROWSABLE = 1;
157
158 /**
159 * Capability for publicly accessible storages (= accessible from the web)
160 */
161 const CAPABILITY_PUBLIC = 2;
162
163 /**
164 * Capability for writable storages. This only signifies writability in
165 * general - this might also be further limited by configuration.
166 */
167 const CAPABILITY_WRITABLE = 4;
168
169 /**
170 * Name of the default processing folder
171 */
172 const DEFAULT_ProcessingFolder = '_processed_';
173
174 /**
175 * @var t3lib_file_Folder
176 */
177 protected $processingFolder;
178
179 /**
180 * Constructor for a storage object.
181 *
182 * @param t3lib_file_Driver_AbstractDriver $driver
183 * @param array $storageRecord The storage record row from the database
184 */
185 public function __construct(t3lib_file_Driver_AbstractDriver $driver, array $storageRecord) {
186 $this->storageRecord = $storageRecord;
187 $this->configuration = $this->getFileFactory()->convertFlexFormDataToConfigurationArray(
188 $storageRecord['configuration']
189 );
190
191 $this->driver = $driver;
192 $this->driver->setStorage($this);
193 $this->driver->initialize();
194 $this->capabilities = ($this->storageRecord['is_browsable'] && $this->driver->hasCapability(self::CAPABILITY_BROWSABLE) ? self::CAPABILITY_BROWSABLE : 0)
195 + ($this->storageRecord['is_public'] && $this->driver->hasCapability(self::CAPABILITY_PUBLIC) ? self::CAPABILITY_PUBLIC : 0)
196 + ($this->storageRecord['is_writable'] && $this->driver->hasCapability(self::CAPABILITY_WRITABLE) ? self::CAPABILITY_WRITABLE : 0);
197
198 $this->processConfiguration();
199 }
200
201 /**
202 * Gets the configuration
203 *
204 * @return array
205 */
206 public function getConfiguration() {
207 return $this->configuration;
208 }
209
210 /**
211 * Sets the configuration.
212 *
213 * @param array $configuration
214 */
215 public function setConfiguration(array $configuration) {
216 $this->configuration = $configuration;
217 }
218
219 /**
220 * Gets the storage record.
221 *
222 * @return array
223 */
224 public function getStorageRecord() {
225 return $this->storageRecord;
226 }
227
228
229 /**
230 * Processes the configuration of this storage.
231 *
232 * @throws InvalidArgumentException If a required configuration option is not set or has an invalid value.
233 * @return void
234 */
235 protected function processConfiguration() {
236 $this->emitPreProcessConfigurationSignal();
237
238 if (isset($this->configuration['baseUri'])) {
239 $this->baseUri = rtrim($this->configuration['baseUri'], '/') . '/';
240 }
241
242 $this->emitPostProcessConfigurationSignal();
243 }
244
245 /**
246 * Returns the base URI of this storage; all files are reachable via URLs
247 * beginning with this string.
248 *
249 * @return string
250 */
251 public function getBaseUri() {
252 return $this->baseUri;
253 }
254
255 /**
256 * Sets the storage that belongs to this storage.
257 *
258 * @param t3lib_file_Driver_AbstractDriver $driver
259 * @return t3lib_file_Storage
260 */
261 public function setDriver(t3lib_file_Driver_AbstractDriver $driver) {
262 $this->driver = $driver;
263 return $this;
264 }
265
266 /**
267 * Returns the driver object belonging to this storage.
268 *
269 * @return t3lib_file_Driver_AbstractDriver
270 */
271 protected function getDriver() {
272 return $this->driver;
273 }
274
275 /**
276 * Deprecated function, don't use it. Will be removed in some later revision.
277 *
278 * @param string $identifier
279 */
280 public function getFolderByIdentifier($identifier) {
281 throw new Exception('Function t3lib_file_Storage::getFolderByIdentifier() has been renamed to just getFolder(). Please fix the metho call.');
282 }
283
284 /**
285 * Deprecated function, don't use it. Will be removed in some later revision.
286 *
287 * @param string $identifier
288 */
289 public function getFileByIdentifier($identifier) {
290 throw new Exception('Function t3lib_file_Storage::getFileByIdentifier() has been renamed to just getFileInfoByIdentifier(). Please fix the metho call.');
291 }
292
293 /**
294 * Returns the name of this storage.
295 *
296 * @return string
297 */
298 public function getName() {
299 return $this->storageRecord['name'];
300 }
301
302 /**
303 * Returns the uid of this storage.
304 *
305 * @return integer
306 */
307 public function getUid() {
308 return (int)$this->storageRecord['uid'];
309 }
310
311 /**
312 * Tells whether there are children in this storage
313 *
314 * @return boolean
315 */
316 public function hasChildren() {
317 return TRUE;
318 }
319
320
321 /*********************************
322 * Capabilities
323 ********************************/
324
325 /**
326 * Returns the capabilities of this storage.
327 *
328 * @return integer
329 * @see CAPABILITY_* constants
330 */
331 public function getCapabilities() {
332 return (int)$this->capabilities;
333 }
334
335 /**
336 * Returns TRUE if this storage has the given capability.
337 *
338 * @param int $capability A capability, as defined in a CAPABILITY_* constant
339 * @return boolean
340 */
341 protected function hasCapability($capability) {
342 return $this->capabilities && $capability;
343 }
344
345 /**
346 * Returns TRUE if this storage is publicly available. This is just a
347 * configuration option and does not mean that it really *is* public. OTOH
348 * a storage that is marked as not publicly available will trigger the file
349 * publishing mechanisms of TYPO3.
350 *
351 * @return boolean
352 */
353 public function isPublic() {
354 return $this->hasCapability(self::CAPABILITY_PUBLIC);
355 }
356
357 /**
358 * Returns TRUE if this storage is writable. This is determined by the
359 * driver and the storage configuration; user permissions are not taken into account.
360 *
361 * @return boolean
362 */
363 public function isWritable() {
364 return $this->hasCapability(self::CAPABILITY_WRITABLE);
365 }
366
367 /**
368 * Returns TRUE if this storage is browsable by a (backend) user of TYPO3.
369 *
370 * @return boolean
371 */
372 public function isBrowsable() {
373 return $this->hasCapability(self::CAPABILITY_BROWSABLE);
374 }
375
376
377 /*********************************
378 * User Permissions / File Mounts
379 ********************************/
380
381 /**
382 * Adds a filemount as a "filter" for users to only work on a subset of a
383 * storage object
384 *
385 * @param string $folderIdentifier
386 * @param array $additionalData
387 * @return void
388 */
389 public function injectFileMount($folderIdentifier, $additionalData = array()) {
390 if (empty($additionalData)) {
391 $additionalData = array(
392 'path' => $folderIdentifier,
393 'title' => $folderIdentifier,
394 'folder' => $this->getFolder($folderIdentifier)
395 );
396 } else {
397 $additionalData['folder'] = $this->getFolder($folderIdentifier);
398 if (!isset($additionalData['title'])) {
399 $additionalData['title'] = $folderIdentifier;
400 }
401 }
402 $this->fileMounts[$folderIdentifier] = $additionalData;
403 }
404
405 /**
406 * Returns all file mounts that are registered with this storage.
407 *
408 * @return array
409 */
410 public function getFileMounts() {
411 return $this->fileMounts;
412 }
413
414 /**
415 * Checks if the given subject is within one of the registered user
416 * filemounts. If not, working with the file is not permitted for the user.
417 *
418 * @param $subject
419 * @return boolean
420 */
421 public function isWithinFileMountBoundaries($subject) {
422 $isWithinFilemount = TRUE;
423 if (is_array($this->fileMounts)) {
424 $isWithinFilemount = FALSE;
425
426 if (!$subject) {
427 $subject = $this->getRootLevelFolder();
428 }
429 $identifier = $subject->getIdentifier();
430
431 // Check if the identifier of the subject is within at
432 // least one of the file mounts
433 foreach ($this->fileMounts as $fileMount) {
434 if ($this->driver->isWithin($fileMount['folder'], $identifier)) {
435 $isWithinFilemount = TRUE;
436 break;
437 }
438 }
439 }
440 return $isWithinFilemount;
441 }
442
443 /**
444 * Adds user permissions to the storage
445 *
446 * @param array $userPermissions
447 * @return void
448 */
449 public function injectUserPermissions(array $userPermissions) {
450 $this->userPermissions = $userPermissions;
451 }
452
453 /**
454 * Check if the ACL settings allow for a certain action
455 * (is a user allowed to read a file or copy a folder)
456 *
457 * @param string $action
458 * @param string $type either File or Folder
459 * @return bool
460 */
461 public function checkUserActionPermission($action, $type) {
462 // TODO decide if we should return TRUE if no permissions are set
463 if (!empty($this->userPermissions)) {
464 $action = strtolower($action);
465 $type = ucfirst(strtolower($type));
466 if ($this->userPermissions[$action . $type] == 0) {
467 return FALSE;
468 } else {
469 return TRUE;
470 }
471 }
472
473 // TODO should the default be really TRUE?
474 return TRUE;
475 }
476
477 /**
478 * Check if a file operation (= action) is allowed on a
479 * File/Folder/Storage (= subject).
480 *
481 * This method, by design, does not throw exceptions or do logging.
482 * Besides the usage from other methods in this class, it is also used by
483 * the File List UI to check whether an action is allowed and whether action
484 * related UI elements should thus be shown (move icon, edit icon, etc.)
485 *
486 * @param string $action, can be read, write, delete
487 * @param t3lib_file_FileInterface $file
488 * @return boolean
489 */
490 public function checkFileActionPermission($action, t3lib_file_FileInterface $file) {
491 // Check 1: Does the user have permission to perform the action? e.g. "readFile"
492 if ($this->checkUserActionPermission($action, 'File') === FALSE) {
493 return FALSE;
494 }
495
496 // Check 2: Does the user has the right to perform the action?
497 // (= is he within the file mount borders)
498 if (is_array($this->fileMounts) && count($this->fileMounts) && !$this->isWithinFileMountBoundaries($file)) {
499 return FALSE;
500 }
501
502
503 $isReadCheck = FALSE;
504 if (in_array($action, array('read'))) {
505 $isReadCheck = TRUE;
506 }
507
508 $isWriteCheck = FALSE;
509 if (in_array($action, array('write', 'delete'))) {
510 $isWriteCheck = TRUE;
511 }
512
513 // Check 3: Check the capabilities of the storage (and the driver)
514 if ($isReadCheck && !$this->isBrowsable()) {
515 return FALSE;
516 }
517 if ($isWriteCheck && !$this->isWritable()) {
518 return FALSE;
519 }
520
521 // Check 4: "File permissions" of the driver
522 $filePermissions = $this->driver->getFilePermissions($file);
523 if ($isReadCheck && !$filePermissions['r']) {
524 return FALSE;
525 }
526 if ($isWriteCheck && !$filePermissions['w']) {
527 return FALSE;
528 }
529
530 return TRUE;
531 }
532
533 /**
534 * Check if a folder operation (= action) is allowed on a Folder
535 *
536 * This method, by design, does not throw exceptions or do logging.
537 * See the checkFileActionPermission() method above for the reasons.
538 *
539 * @param string $action
540 * @param t3lib_file_Folder $folder
541 * @return boolean
542 */
543 public function checkFolderActionPermission($action, t3lib_file_Folder $folder = NULL) {
544 // Check 1: Does the user have permission to perform the action? e.g. "writeFolder"
545 if ($this->checkUserActionPermission($action, 'Folder') === FALSE) {
546 return FALSE;
547 }
548
549 // Check 2: Does the user has the right to perform the action?
550 // (= is he within the file mount borders)
551 if (is_array($this->fileMounts) && count($this->fileMounts) && !$this->isWithinFileMountBoundaries($folder)) {
552 return FALSE;
553 }
554
555 $isReadCheck = FALSE;
556 if (in_array($action, array('read'))) {
557 $isReadCheck = TRUE;
558 }
559
560 $isWriteCheck = FALSE;
561 if (in_array($action, array('write', 'delete', 'deleteRecursive'))) {
562 $isWriteCheck = TRUE;
563 }
564
565 // Check 3: Check the capabilities of the storage (and the driver)
566 if ($isReadCheck && !$this->isBrowsable()) {
567 return FALSE;
568 }
569 if ($isWriteCheck && !$this->isWritable()) {
570 return FALSE;
571 }
572
573 // Check 4: "Folder permissions" of the driver
574 $folderPermissions = $this->driver->getFolderPermissions($folder);
575 if ($isReadCheck && !$folderPermissions['r']) {
576 return FALSE;
577 }
578 if ($isWriteCheck && !$folderPermissions['w']) {
579 return FALSE;
580 }
581
582 return TRUE;
583 }
584
585 /**
586 * If the fileName is given, check it against the
587 * TYPO3_CONF_VARS[BE][fileDenyPattern] + and if the file extension is allowed
588 *
589 * @param string $fileName Full filename
590 * @return boolean TRUE if extension/filename is allowed
591 */
592 protected function checkFileExtensionPermission($fileName) {
593 $isAllowed = t3lib_div::verifyFilenameAgainstDenyPattern($fileName);
594
595 if ($isAllowed) {
596 $fileInfo = t3lib_div::split_fileref($fileName);
597
598 // Set up the permissions for the file extension
599 $fileExtensionPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']['webspace'];
600 $fileExtensionPermissions['allow'] = t3lib_div::uniqueList(strtolower($fileExtensionPermissions['allow']));
601 $fileExtensionPermissions['deny'] = t3lib_div::uniqueList(strtolower($fileExtensionPermissions['deny']));
602
603 $fileExtension = strtolower($fileInfo['fileext']);
604 if ($fileExtension !== '') {
605 // If the extension is found amongst the allowed types, we return TRUE immediately
606 if ($fileExtensionPermissions['allow'] === '*' || t3lib_div::inList($fileExtensionPermissions['allow'], $fileExtension)) {
607 return TRUE;
608 }
609 // If the extension is found amongst the denied types, we return FALSE immediately
610 if ($fileExtensionPermissions['deny'] === '*' || t3lib_div::inList($fileExtensionPermissions['deny'], $fileExtension)) {
611 return FALSE;
612 }
613 // If no match we return TRUE
614 return TRUE;
615
616 // No file extension
617 } else {
618 if ($fileExtensionPermissions['allow'] === '*') {
619 return TRUE;
620 }
621 if ($fileExtensionPermissions['deny'] === '*') {
622 return FALSE;
623 }
624 return TRUE;
625 }
626 }
627 return FALSE;
628 }
629
630 /********************
631 * FILE ACTIONS
632 ********************/
633
634 /**
635 * Moves a file from the local filesystem to this storage.
636 *
637 * @param string $localFilePath The file on the server's hard disk to add.
638 * @param t3lib_file_Folder $targetFolder The target path, without the fileName
639 * @param string $fileName The fileName. If not set, the local file name is used.
640 * @param string $conflictMode possible value are 'cancel', 'replace', 'changeName'
641 * @return t3lib_file_FileInterface
642 */
643 public function addFile($localFilePath, t3lib_file_Folder $targetFolder, $fileName = '', $conflictMode = 'changeName') {
644 // TODO check permissions (write on target, upload, ...)
645
646 if (!file_exists($localFilePath)) {
647 throw new InvalidArgumentException('File "' . $localFilePath .'" does not exist.', 1319552745);
648 }
649
650 $targetFolder = $targetFolder ? $targetFolder : $this->getDefaultFolder();
651 $fileName = $fileName ? $fileName : basename($localFilePath);
652
653 if ($conflictMode === 'cancel' && $this->driver->fileExistsInFolder($fileName, $targetFolder)) {
654 throw new t3lib_file_exception_ExistingTargetFileNameException('File "' . $fileName . '" already exists in folder '
655 . $targetFolder->getIdentifier(), 1322121068);
656 } elseif ($conflictMode === 'changeName') {
657 $fileName = $this->getUniqueName($targetFolder, $fileName);
658 }
659 // We do not care whether the file exists if $conflictMode is "replace",
660 // so just use the name as is in that case
661
662 return $this->driver->addFile($localFilePath, $targetFolder, $fileName);
663 }
664
665 /**
666 * Creates a (cryptographic) hash for a file.
667 *
668 * @param t3lib_file_FileInterface $fileObject
669 * @param $hash
670 * @return string
671 */
672 public function hashFile(t3lib_file_FileInterface $fileObject, $hash) {
673 return $this->driver->hash($fileObject, $hash);
674 }
675
676 /**
677 * Returns a publicly accessible URL for a file.
678 *
679 * WARNING: Access to the file may be restricted by further means, e.g.
680 * some web-based authentication. You have to take care of this yourself.
681 *
682 * @param t3lib_file_FileInterface $fileObject The file object
683 * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver)
684 * @return string
685 */
686 public function getPublicUrlForFile(t3lib_file_FileInterface $fileObject, $relativeToCurrentScript = FALSE) {
687 return $this->driver->getPublicUrl($fileObject, $relativeToCurrentScript);
688 }
689
690 /**
691 * Returns a publicly accessible URL for a file.
692 *
693 * @param t3lib_file_FileInterface $fileObject The file object
694 * @param string $context
695 * @param array $configuration
696 * @return t3lib_file_ProcessedFile
697 */
698 public function processFile(t3lib_file_FileInterface $fileObject, $context, array $configuration) {
699 $processedFile = $this->getFileFactory()->getProcessedFileObject(
700 $fileObject,
701 $context,
702 $configuration
703 );
704
705 // Pre-process the file by an accordant slot
706 $this->emitPreFileProcess($processedFile, $fileObject, $context, $configuration);
707
708 // Only handle the file is not processed yet
709 // (maybe modified or already processed by a signal)
710 // or (in case of preview images) already in the DB/in the processing folder
711 if (!$processedFile->isProcessed()) {
712 $processedFile = $this->getFileProcessingService()->process(
713 $processedFile,
714 $fileObject,
715 $context,
716 $configuration
717 );
718 }
719
720 // Post-process (enrich) the file by an accordant slot
721 $this->emitPostFileProcess($processedFile, $fileObject, $context, $configuration);
722
723 return $processedFile;
724 }
725
726 /**
727 * Copies a file from the storage for local processing.
728 *
729 * @param t3lib_file_FileInterface $fileObject
730 * @param bool $writable
731 * @return string Path to local file (either original or copied to some temporary local location)
732 */
733 public function getFileForLocalProcessing(t3lib_file_FileInterface $fileObject, $writable = TRUE) {
734 $filePath = $this->driver->getFileForLocalProcessing($fileObject, $writable);
735 touch($filePath, $fileObject->getModificationTime());
736
737 return $filePath;
738 }
739
740 /**
741 * Get file by identifier
742 *
743 * @param string $identifier
744 * @return t3lib_file_FileInterface
745 */
746 public function getFile($identifier) {
747 return $this->driver->getFile($identifier);
748 }
749
750
751 /**
752 * Get file by identifier
753 *
754 * @param string $identifier
755 * @return t3lib_file_FileInterface
756 */
757 public function getFileInfo($file) {
758 return $this->driver->getFileInfo($file);
759 }
760
761 /**
762 * Get file by identifier
763 *
764 * @deprecated To be removed before final release of FAL. Use combination of getFileInfoByIdentifier() with a file object as argument instead.
765 *
766 * @param string $identifier
767 * @return t3lib_file_FileInterface
768 */
769 public function getFileInfoByIdentifier($identifier) {
770 return $this->driver->getFileInfoByIdentifier($identifier);
771 }
772
773
774 /**
775 * Returns a list of files in a given path.
776 *
777 * @param string $path The path to list
778 * @param string $pattern The pattern the files have to match
779 * @param integer $start The position to start the listing; if not set or 0, start from the beginning
780 * @param integer $numberOfItems The number of items to list; if not set, return all items
781 * @param bool $excludeHiddenFiles Set this to TRUE to exclude hidden files (starting with a dot)
782 * @param bool $loadIndexRecords If set to TRUE, the index records for all files are loaded from the database. This can greatly improve performance of this method, especially with a lot of files.
783 * @return array Information about the files found.
784 */
785 // TODO check if we should use a folder object instead of $path
786 // TODO add unit test for $loadIndexRecords
787 public function getFileList($path, $pattern = '', $start = 0, $numberOfItems = 0, $excludeHiddenFiles = TRUE, $loadIndexRecords = TRUE) {
788 $rows = array();
789 if ($loadIndexRecords) {
790 /** @var $repository t3lib_file_Repository_FileRepository */
791 $repository = t3lib_div::makeInstance('t3lib_file_Repository_FileRepository');
792 $rows = $repository->getFileIndexRecordsForFolder($this->getFolder($path));
793 }
794
795 $items = $this->driver->getFileList($path, $pattern, $start, $numberOfItems, $excludeHiddenFiles, $rows);
796 uksort($items, 'strnatcasecmp');
797
798 return $items;
799 }
800
801 /**
802 * Returns TRUE if the specified file exists.
803 *
804 * @param string $identifier
805 * @return boolean
806 */
807 public function hasFile($identifier) {
808 // @todo: access check?
809 return $this->driver->fileExists($identifier);
810 }
811
812 /**
813 * Checks if the queried file in the given folder exists.
814 *
815 * @param string $fileName
816 * @param t3lib_file_Folder $folder
817 * @return boolean
818 */
819 public function hasFileInFolder($fileName, t3lib_file_Folder $folder) {
820 return $this->driver->fileExistsInFolder($fileName, $folder);
821 }
822
823
824 /**
825 * Get contents of a file object
826 *
827 * @param t3lib_file_FileInterface $file
828 * @return string
829 */
830 public function getFileContents($file) {
831 // Check if $file is readable
832 if (!$this->checkFileActionPermission('read', $file)) {
833 throw new t3lib_file_exception_InsufficientFileReadPermissionsException('Reading file "'
834 . $file->getIdentifier() . '" is not allowed.', 1330121089);
835 }
836
837 return $this->driver->getFileContents($file);
838 }
839
840 /**
841 * Set contents of a file object.
842 *
843 * @param t3lib_file_AbstractFile $file
844 * @param string $contents
845 * @return integer The number of bytes written to the file
846 */
847 public function setFileContents(t3lib_file_AbstractFile $file, $contents) {
848 // TODO does setting file contents require update permission?
849 // Check if user is allowed to update
850 if (!$this->checkUserActionPermission('update', 'File')) {
851 throw new t3lib_file_exception_InsufficientUserPermissionsException('Updating file "'
852 . $file->getIdentifier() . '" not allowed for user.', 1330121117);
853 }
854
855 // Check if $file is writable
856 if (!$this->checkFileActionPermission('write', $file)) {
857 throw new t3lib_file_exception_InsufficientFileWritePermissionsException('Writing to file "'
858 . $file->getIdentifier() . '" is not allowed.', 1330121088);
859 }
860
861 // Call driver method to update the file and update file properties afterwards
862 try {
863 $result = $this->driver->setFileContents($file, $contents);
864
865 $fileInfo = $this->driver->getFileInfo($file);
866 $fileInfo['sha1'] = $this->driver->hash($file, 'sha1');
867 $file->updateProperties($fileInfo);
868 } catch (RuntimeException $e) {
869 throw $e;
870 }
871
872 return $result;
873 }
874
875 /**
876 * Creates a new file
877 *
878 * previously in t3lib_extFileFunc::func_newfile()
879 *
880 * @param string $fileName
881 * @param t3lib_file_Folder $targetFolderObject
882 * @return t3lib_file_FileInterface The file object
883 */
884 public function createFile($fileName, t3lib_file_Folder $targetFolderObject) {
885 if (!$this->checkFolderActionPermission('createFile', $targetFolderObject)) {
886 throw new t3lib_file_exception_InsufficientFolderWritePermissionsException('You are not allowed to create directories on this storage "' . $targetFolderObject->getIdentifier() . '"', 1323059807);
887 }
888 return $this->driver->createFile($fileName, $targetFolderObject);
889 }
890
891 /**
892 * Previously in t3lib_extFileFunc::deleteFile()
893 * @param $fileObject t3lib_file_FileInterface
894 * @return bool TRUE if deletion succeeded
895 *
896 * TODO throw FileInUseException when the file is still used anywhere
897 */
898 public function deleteFile($fileObject) {
899 if (!$this->checkFileActionPermission('delete', $fileObject)) {
900 throw new t3lib_file_exception_InsufficientFileAccessPermissionsException('You are not allowed to delete the file "' . $fileObject->getIdentifier() . "'", 1319550425);
901 }
902
903 $result = $this->driver->deleteFile($fileObject);
904
905 if ($result === FALSE) {
906 throw new t3lib_file_exception_FileOperationErrorException('Deleting the file "' . $fileObject->getIdentifier() . "' failed.", 1329831691);
907 }
908
909 // Mark the file object as deleted
910 $fileObject->setDeleted();
911
912 return TRUE;
913 }
914
915 /**
916 * Previously in t3lib_extFileFunc::func_copy()
917 * copies a source file (from any location) in to the target
918 * folder, the latter has to be part of this storage
919 *
920 * @param t3lib_file_FileInterface $file
921 * @param t3lib_file_Folder $targetFolder
922 * @param string $conflictMode "overrideExistingFile", "renameNewFile", "cancel"
923 * @param string $targetFileName an optional destination fileName
924 * @return t3lib_file_FileInterface
925 */
926 public function copyFile(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder, $targetFileName = NULL, $conflictMode = 'renameNewFile') {
927 $this->emitPreFileCopySignal($file, $targetFolder);
928
929 $this->checkFileCopyPermissions($file, $targetFolder, $targetFileName);
930
931 if ($targetFileName === NULL) {
932 $targetFileName = $file->getName();
933 }
934
935 // File exists and we should abort, let's abort
936 if ($conflictMode === 'cancel' && $targetFolder->hasFile($targetFileName)) {
937 throw new t3lib_file_exception_ExistingTargetFileNameException('The target file already exists.', 1320291063);
938 }
939
940 // File exists and we should find another name, let's find another one
941 if ($conflictMode === 'renameNewFile' && $targetFolder->hasFile($targetFileName)) {
942 $targetFileName = $this->getUniqueName($targetFolder, $targetFileName);
943 }
944
945 $sourceStorage = $file->getStorage();
946 // Call driver method to create a new file from an existing file object,
947 // and return the new file object
948 try {
949 if ($sourceStorage == $this) {
950 $newFileObject = $this->driver->copyFileWithinStorage($file, $targetFolder, $targetFileName);
951 } else {
952 $tempPath = $file->getForLocalProcessing();
953 $newFileObject = $this->driver->addFile($tempPath, $targetFolder, $targetFileName);
954 // TODO update metadata
955 }
956 } catch (t3lib_file_exception_AbstractFileOperationException $e) {
957 throw $e;
958 }
959
960 $this->emitPostFileCopySignal($file, $targetFolder);
961
962 return $newFileObject;
963 }
964
965 /**
966 * Check if a file has the permission to be uploaded to a Folder/Storage,
967 * if not throw an exception
968 *
969 * @param string $localFilePath the temporary file name from $_FILES['file1']['tmp_name']
970 * @param t3lib_file_Folder $targetFolder
971 * @param string $targetFileName the destination file name $_FILES['file1']['name']
972 * @param int $uploadedFileSize
973 * @return void
974 */
975 protected function checkFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileSize) {
976 // Makes sure the user is allowed to upload
977 if (!$this->checkUserActionPermission('upload', 'File')) {
978 throw new t3lib_file_exception_InsufficientUserPermissionsException('You are not allowed to upload files to this storage "' . $this->getUid() . '"', 1322112430);
979 }
980
981 // Makes sure this is an uploaded file
982 if (!is_uploaded_file($localFilePath)) {
983 throw new t3lib_file_exception_UploadException("The upload has failed, no uploaded file found!", 1322110455);
984 }
985
986 // Max upload size (kb) for files.
987 $maxUploadFileSize = t3lib_div::getMaxUploadFileSize() * 1024;
988 if ($uploadedFileSize >= $maxUploadFileSize) {
989 throw new t3lib_file_exception_UploadSizeException("The uploaded file exceeds the size-limit of $maxUploadFileSize bytes", 1322110041);
990 }
991
992 // Check if targetFolder is writable
993 if (!$this->checkFolderActionPermission('write', $targetFolder)) {
994 throw new t3lib_file_exception_InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1322120356);
995 }
996
997 // Check for a valid file extension
998 if (!$this->checkFileExtensionPermission($targetFileName)) {
999 throw new t3lib_file_exception_IllegalFileExtensionException("Extension of file name is not allowed in \"$targetFileName\"!", 1322120271);
1000 }
1001 }
1002
1003 /**
1004 * Check if a file has the permission to be copied on a File/Folder/Storage,
1005 * if not throw an exception
1006 *
1007 * @param t3lib_file_FileInterface $file
1008 * @param t3lib_file_Folder $targetFolder
1009 * @param string $targetFileName
1010 * @return void
1011 */
1012 protected function checkFileCopyPermissions(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder, $targetFileName) {
1013 // Check if targetFolder is within this storage, this should never happen
1014 if ($this->getUid() != $targetFolder->getStorage()->getUid()) {
1015 throw new t3lib_file_exception_AbstractFileException('The operation of the folder cannot be called by this storage "' . $this->getUid() . '"', 1319550405);
1016 }
1017
1018 // Check if user is allowed to copy
1019 if (!$this->checkUserActionPermission('copy', 'File')) {
1020 throw new t3lib_file_exception_InsufficientUserPermissionsException('You are not allowed to copy files to this storage "' . $this->getUid() . '"', 1319550415);
1021 }
1022
1023 // Check if $file is readable
1024 if (!$this->checkFileActionPermission('read', $file)) {
1025 throw new t3lib_file_exception_InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . "'", 1319550425);
1026 }
1027
1028 // Check if targetFolder is writable
1029 if (!$this->checkFolderActionPermission('write', $targetFolder)) {
1030 throw new t3lib_file_exception_InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319550435);
1031 }
1032
1033 // Check for a valid file extension
1034 if (!$this->checkFileExtensionPermission($targetFileName)) {
1035 throw new t3lib_file_exception_IllegalFileExtensionException('You are not allowed to copy a file of that type.', 1319553317);
1036 }
1037 }
1038
1039 /**
1040 * Moves a $file into a $targetFolder
1041 * the target folder has to be part of this storage
1042 *
1043 * previously in t3lib_extFileFunc::func_move()
1044 * @param t3lib_file_FileInterface $file
1045 * @param t3lib_file_Folder $targetFolder
1046 * @param string $conflictMode "overrideExistingFile", "renameNewFile", "cancel"
1047 * @param string $targetFileName an optional destination fileName
1048 * @return t3lib_file_FileInterface
1049 */
1050 public function moveFile($file, $targetFolder, $targetFileName = NULL, $conflictMode = 'renameNewFile') {
1051 $this->checkFileMovePermissions($file, $targetFolder);
1052
1053 if ($targetFileName === NULL) {
1054 $targetFileName = $file->getName();
1055 }
1056
1057 if ($targetFolder->hasFile($targetFileName)) {
1058 // File exists and we should abort, let's abort
1059 if ($conflictMode === 'renameNewFile') {
1060 $targetFileName = $this->getUniqueName($targetFolder, $targetFileName);
1061
1062 // Cancel if requested so
1063 } elseif ($conflictMode === 'cancel') {
1064 throw new t3lib_file_exception_ExistingTargetFileNameException('The target file already exists', 1329850997);
1065 }
1066 // When $conflictMode is "overrideExistingFile", just ignore the naming conflict
1067 // TODO check what to do with an existing index record for the target file then
1068 }
1069
1070 $this->emitPreFileMoveSignal($file, $targetFolder);
1071
1072 $sourceStorage = $file->getStorage();
1073 // Call driver method to move the file that also updates the file
1074 // object properties
1075 try {
1076 if ($sourceStorage == $this) {
1077 $newIdentifier = $this->driver->moveFileWithinStorage($file, $targetFolder, $targetFileName);
1078
1079 $this->updateFile($file, $newIdentifier);
1080 } else {
1081 $tempPath = $file->getForLocalProcessing();
1082 $newIdentifier = $this->driver->addFileRaw($tempPath, $targetFolder, $targetFileName);
1083 $sourceStorage->driver->deleteFileRaw($file->getIdentifier());
1084
1085 $this->updateFile($file, $newIdentifier, $this);
1086 }
1087 } catch (t3lib_exception $e) {
1088 echo $e->getMessage();
1089 // TODO echo should be changed to something useful
1090 // TODO rollback things that have happened
1091 // TODO emit FileMoveFailedSignal?
1092 }
1093
1094 $this->emitPostFileMoveSignal($file, $targetFolder);
1095
1096 return $file;
1097 }
1098
1099 /**
1100 * Updates the properties of a file object with some that are freshly
1101 * fetched from the driver.
1102 *
1103 * @param t3lib_file_AbstractFile $file
1104 * @param string $identifier The identifier of the file. If set, this will overwrite the file object's identifier (use e.g. after moving a file)
1105 * @param t3lib_file_Storage $storage
1106 * @return void
1107 */
1108 protected function updateFile(t3lib_file_AbstractFile $file, $identifier = '', $storage = NULL) {
1109 if ($identifier === '') {
1110 $identifier = $file->getIdentifier();
1111 }
1112 $fileInfo = $this->driver->getFileInfoByIdentifier($identifier);
1113 // TODO extend mapping
1114 $newProperties = array(
1115 'storage' => $fileInfo['storage'],
1116 'identifier' => $fileInfo['identifier'],
1117 'tstamp' => $fileInfo['mtime'],
1118 'crdate' => $fileInfo['ctime'],
1119 'mime_type' => $fileInfo['mimetype'],
1120 'size' => $fileInfo['size'],
1121 'tstamp' => $fileInfo['mtime']
1122 );
1123 if ($storage !== NULL) {
1124 $newProperties['storage'] = $storage->getUid();
1125 }
1126
1127 $file->updateProperties($newProperties);
1128
1129 /** @var $fileRepository t3lib_file_Repository_FileRepository */
1130 $fileRepository = t3lib_div::makeInstance('t3lib_file_Repository_FileRepository');
1131 $fileRepository->update($file);
1132 }
1133
1134 /**
1135 * Checks for permissions to move a file.
1136 *
1137 * @throws RuntimeException
1138 * @throws t3lib_file_exception_InsufficientFileReadPermissionsException
1139 * @throws t3lib_file_exception_InsufficientFileWritePermissionsException
1140 * @throws t3lib_file_exception_InsufficientFolderAccessPermissionsException
1141 * @throws t3lib_file_exception_InsufficientUserPermissionsException
1142 * @param t3lib_file_FileInterface $file
1143 * @param t3lib_file_Folder $targetFolder
1144 * @return void
1145 */
1146 protected function checkFileMovePermissions(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder) {
1147 // Check if targetFolder is within this storage
1148 if ($this->getUid() != $targetFolder->getStorage()->getUid()) {
1149 throw new RuntimeException();
1150 }
1151
1152 // Check if user is allowed to move
1153 if (!$this->checkUserActionPermission('move', 'File')) {
1154 throw new t3lib_file_exception_InsufficientUserPermissionsException('You are not allowed to move files to storage "' . $this->getUid() . '"', 1319219349);
1155 }
1156
1157 // Check if $file is readable
1158 if (!$this->checkFileActionPermission('read', $file)) {
1159 throw new t3lib_file_exception_InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . "'", 1319219349);
1160 }
1161
1162 // Check if $file is writable
1163 if (!$this->checkFileActionPermission('write', $file)) {
1164 throw new t3lib_file_exception_InsufficientFileWritePermissionsException('You are not allowed to move the file "' . $file->getIdentifier() . "'", 1319219349);
1165 }
1166
1167 // Check if targetFolder is writable
1168 if (!$this->checkFolderActionPermission('write', $targetFolder)) {
1169 throw new t3lib_file_exception_InsufficientFolderAccessPermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319219349);
1170 }
1171 }
1172
1173 /**
1174 * Previously in t3lib_extFileFunc::func_rename()
1175 *
1176 * @param t3lib_file_FileInterface $file
1177 * @param string $targetFileName
1178 * @return t3lib_file_FileInterface
1179 */
1180 // TODO add $conflictMode setting
1181 public function renameFile($file, $targetFileName) {
1182
1183 // The name should be different from the current.
1184 if ($file->getIdentifier() == $targetFileName) {
1185 return $file;
1186 }
1187
1188 // Check if user is allowed to rename
1189 if (!$this->checkUserActionPermission('rename', 'File')) {
1190 throw new t3lib_file_exception_InsufficientUserPermissionsException('You are not allowed to rename files."', 1319219349);
1191 }
1192
1193 // Check if $file is readable
1194 if (!$this->checkFileActionPermission('read', $file)) {
1195 throw new t3lib_file_exception_InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . "'", 1319219349);
1196 }
1197
1198 // Check if $file is writable
1199 if (!$this->checkFileActionPermission('write', $file)) {
1200 throw new t3lib_file_exception_InsufficientFileWritePermissionsException('You are not allowed to rename the file "' . $file->getIdentifier() . "'", 1319219349);
1201 }
1202
1203 // Call driver method to rename the file that also updates the file
1204 // object properties
1205 try {
1206 $newIdentifier = $this->driver->renameFile($file, $targetFileName);
1207
1208 $this->updateFile($file, $newIdentifier);
1209 /** @var $fileRepository t3lib_file_Repository_FileRepository */
1210 $fileRepository = t3lib_div::makeInstance('t3lib_file_Repository_FileRepository');
1211 $fileRepository->update($file);
1212 } catch(RuntimeException $e) {
1213 // rename failed (maybe because file existed?)
1214 // todo: bubble exception?
1215 }
1216
1217 return $file;
1218 }
1219
1220 /**
1221 * Replaces a file with a local file (e.g. a freshly uploaded file)
1222 *
1223 * @param t3lib_file_FileInterface $file
1224 * @param string $localFilePath
1225 * @return t3lib_file_FileInterface
1226 */
1227 public function replaceFile(t3lib_file_FileInterface $file, $localFilePath) {
1228 if (!file_exists($localFilePath)) {
1229 throw new InvalidArgumentException('File "' . $localFilePath . '" does not exist.', 1325842622);
1230 }
1231
1232 // TODO check permissions
1233
1234 $this->emitPreFileReplaceSignal($file, $localFilePath);
1235
1236 $result = $this->driver->replaceFile($file, $localFilePath);
1237
1238 $this->emitPostFileReplaceSignal($file, $localFilePath);
1239
1240 return $result;
1241 }
1242
1243 /**
1244 * Adds an uploaded file into the Storage. Previously in t3lib_extFileFunc::file_upload()
1245 *
1246 * @param array $uploadedFileData contains information about the uploaded file given by $_FILES['file1']
1247 * @param t3lib_file_Folder $targetFolder the target folder
1248 * @param string $targetFileName the file name to be written
1249 * @param string $conflictMode possible value are 'cancel', 'replace'
1250 * @return t3lib_file_FileInterface The file object
1251 */
1252 public function addUploadedFile(array $uploadedFileData, t3lib_file_Folder $targetFolder = NULL, $targetFileName = NULL, $conflictMode = 'cancel') {
1253 $localFilePath = $uploadedFileData['tmp_name'];
1254 if ($targetFolder === NULL) {
1255 $targetFolder = $this->getDefaultFolder();
1256 }
1257
1258 if ($targetFileName === NULL) {
1259 $targetFileName = $uploadedFileData['name'];
1260 }
1261
1262 // Handling $conflictMode is delegated to addFile()
1263 $this->checkFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileData['size']);
1264
1265 $resultObject = $this->addFile($localFilePath, $targetFolder, $targetFileName, $conflictMode);
1266 return $resultObject;
1267 }
1268
1269 /********************
1270 * FOLDER ACTIONS
1271 ********************/
1272
1273 /**
1274 * Returns an array with all file objects in a folder and its subfolders, with the file identifiers as keys.
1275 *
1276 * @param t3lib_file_Folder $folder
1277 * @return t3lib_file_File[]
1278 */
1279 protected function getAllFileObjectsInFolder(t3lib_file_Folder $folder) {
1280 $files = array();
1281 $folderQueue = array($folder);
1282
1283 while (!empty($folderQueue)) {
1284 $folder = array_shift($folderQueue);
1285 foreach ($folder->getSubfolders() as $subfolder) {
1286 $folderQueue[] = $subfolder;
1287 }
1288
1289 foreach ($folder->getFiles() as $file) {
1290 $files[$file->getIdentifier()] = $file;
1291 }
1292 }
1293
1294 return $files;
1295 }
1296
1297 /**
1298 * Moves a folder. If you want to move a folder from this storage to another
1299 * one, call this method on the target storage, otherwise you will get an exception.
1300 *
1301 * @param t3lib_file_Folder $folderToMove The folder to move.
1302 * @param t3lib_file_Folder $targetParentFolder The target parent folder
1303 * @param string $newFolderName
1304 * @param string $conflictMode How to handle conflicts; one of "overrideExistingFile", "renameNewFolder", "cancel"
1305 * @return t3lib_file_Folder
1306 */
1307 // TODO add tests
1308 public function moveFolder(t3lib_file_Folder $folderToMove, t3lib_file_Folder $targetParentFolder, $newFolderName = NULL, $conflictMode = 'renameNewFolder') {
1309 $sourceStorage = $folderToMove->getStorage();
1310
1311 if (!$targetParentFolder->getStorage() == $this) {
1312 throw new InvalidArgumentException('Cannot move a folder into a folder that does not belong to this storage.', 1325777289);
1313 }
1314
1315 $newFolderName = $newFolderName ? $newFolderName : $folderToMove->getName();
1316
1317 // TODO check if folder already exists in $targetParentFolder, handle this conflict then
1318
1319 $this->emitPreFolderMoveSignal($folderToMove, $targetParentFolder, $newFolderName);
1320
1321 // Get all file objects now so we are able to update them after moving the folder
1322 $fileObjects = $this->getAllFileObjectsInFolder($folderToMove);
1323 try {
1324 if ($sourceStorage == $this) {
1325 $fileMappings = $this->driver->moveFolderWithinStorage($folderToMove, $targetParentFolder, $newFolderName);
1326
1327 } else {
1328 $fileMappings = $this->moveFolderBetweenStorages($folderToMove, $targetParentFolder, $newFolderName);
1329 }
1330
1331 // Update the identifier and storage of all file objects
1332 foreach ($fileObjects as $oldIdentifier => $fileObject) {
1333 $newIdentifier = $fileMappings[$oldIdentifier];
1334 $fileObject->updateProperties(array('storage' => $this, 'identifier' => $newIdentifier));
1335 }
1336 } catch (t3lib_exception $e) {
1337 throw $e;
1338 // TODO rollback things that have happened
1339 }
1340
1341 $this->emitPostFolderMoveSignal($folderToMove, $targetParentFolder, $newFolderName);
1342 }
1343
1344 /**
1345 * Moves the given folder from a different storage to the target folder in this storage.
1346 *
1347 * @param t3lib_file_Folder $folderToMove
1348 * @param t3lib_file_Folder $targetParentFolder
1349 * @param string $newFolderName
1350 * @return array Mapping of old file identifiers to new ones
1351 */
1352 protected function moveFolderBetweenStorages(t3lib_file_Folder $folderToMove, t3lib_file_Folder $targetParentFolder, $newFolderName = NULL) {
1353 // This is not implemented for now as moving files between storages might cause quite some headaches when
1354 // something goes wrong. It is also not that common of a use case, so it does not hurt that much to leave it out
1355 // for now.
1356 throw new BadMethodCallException('Moving folders between storages is not implemented.');
1357 }
1358
1359 /**
1360 * Copy folder
1361 *
1362 * @param t3lib_file_Folder $folderToCopy The folder to copy
1363 * @param t3lib_file_Folder $targetParentFolder The target folder
1364 * @param string $newFolderName
1365 * @param string $conflictMode "overrideExistingFolder", "renameNewFolder", "cancel"
1366 * @return t3lib_file_Folder The new (copied) folder object
1367 */
1368 public function copyFolder(t3lib_file_Folder $folderToCopy, t3lib_file_Folder $targetParentFolder, $newFolderName = NULL, $conflictMode = 'renameNewFolder') {
1369 // TODO implement the $conflictMode handling
1370 // TODO permission checks
1371
1372 $newFolderName = $newFolderName ? $newFolderName : $folderToCopy->getName();
1373
1374 $this->emitPreFolderCopySignal($folderToCopy, $targetParentFolder, $newFolderName);
1375
1376 $sourceStorage = $folderToCopy->getStorage();
1377 // call driver method to move the file
1378 // that also updates the file object properties
1379 try {
1380 if ($sourceStorage == $this) {
1381 $this->driver->copyFolderWithinStorage($folderToCopy, $targetParentFolder, $newFolderName);
1382 } else {
1383 $this->copyFolderBetweenStorages($folderToCopy, $targetParentFolder, $newFolderName);
1384 }
1385 } catch (t3lib_exception $e) {
1386 echo $e->getMessage();
1387 // TODO rollback things that have happened
1388 }
1389
1390 $this->emitPostFolderCopySignal($folderToCopy, $targetParentFolder, $newFolderName);
1391 }
1392
1393 /**
1394 * Moves files between storages
1395 *
1396 * @param t3lib_file_Folder $folderToMove
1397 * @param t3lib_file_Folder $targetParentFolder
1398 * @param null $newFolderName
1399 * @return void
1400 */
1401 protected function copyFolderBetweenStorages(t3lib_file_Folder $folderToMove, t3lib_file_Folder $targetParentFolder, $newFolderName = NULL) {
1402 throw new RuntimeException('Not yet implemented!', 1330262731);
1403 /**
1404 * TODO:
1405 * - get all folders, call this method for each of them
1406 * - get all files
1407 * - get a local copy
1408 * - put it into the other storage
1409 */
1410
1411 }
1412
1413 /**
1414 * Previously in t3lib_extFileFunc::folder_move()
1415 *
1416 * @throws RuntimeException if an error occurs during renaming
1417 * @param t3lib_file_Folder $folderObject
1418 * @param string $newName
1419 * @return bool TRUE if the operation succeeded
1420 */
1421 public function renameFolder($folderObject, $newName) {
1422 // TODO unit tests
1423 // TODO access checks
1424
1425 if ($this->driver->folderExistsInFolder($newName, $folderObject)) {
1426 throw new InvalidArgumentException("The folder $newName already exists in folder " . $folderObject->getIdentifier(), 1325418870);
1427 }
1428
1429 $this->emitPreFolderRenameSignal($folderObject, $newName);
1430
1431 $fileObjects = $this->getAllFileObjectsInFolder($folderObject);
1432 try {
1433 $fileMappings = $this->driver->renameFolder($folderObject, $newName);
1434
1435 // Update the identifier of all file objects
1436 foreach ($fileObjects as $oldIdentifier => $fileObject) {
1437 $newIdentifier = $fileMappings[$oldIdentifier];
1438 $fileObject->updateProperties(array('identifier' => $newIdentifier));
1439 }
1440 } catch (Exception $e) {
1441 throw $e;
1442 }
1443
1444 $this->emitPostFolderRenameSignal($folderObject, $newName);
1445 }
1446
1447 /**
1448 * Previously in t3lib_extFileFunc::folder_delete()
1449 *
1450 * @param t3lib_file_Folder $folderObject
1451 * @param bool $deleteRecursively
1452 * @return bool
1453 */
1454 public function deleteFolder($folderObject, $deleteRecursively = FALSE) {
1455
1456 if (!$this->checkFolderActionPermission('delete', $folderObject)) {
1457 throw new t3lib_file_exception_InsufficientFileAccessPermissionsException('You are not allowed to access the folder "' . $folderObject->getIdentifier() . "'", 1323423953);
1458 }
1459
1460 if ($this->driver->isFolderEmpty($folderObject) && !$deleteRecursively) {
1461 throw new RuntimeException('Could not delete folder "' . $folderObject->getIdentifier() . '" because it is not empty.', 1325952534);
1462 }
1463
1464 $this->emitPreFolderDeleteSignal($folderObject);
1465
1466 $this->driver->deleteFolder($folderObject, $deleteRecursively);
1467
1468 $this->emitPostFolderDeleteSignal($folderObject);
1469 }
1470
1471 /**
1472 * Returns a list of files in a given path.
1473 *
1474 * @param string $path The path to list
1475 * @param string $pattern The pattern the files have to match
1476 * @param integer $start The position to start the listing; if not set or 0, start from the beginning
1477 * @param integer $numberOfItems The number of items to list; if not set, return all items
1478 * @param bool $excludeHiddenFolders Set to TRUE to exclude hidden folders (starting with a dot)
1479 * @return array Information about the folders found.
1480 */
1481 public function getFolderList($path, $pattern = '', $start = 0, $numberOfItems = 0, $excludeHiddenFolders = TRUE) {
1482 $items = $this->driver->getFolderList($path, $pattern, $start, $numberOfItems, $excludeHiddenFolders);
1483
1484 // Exclude the _processed_ folder, so it won't get indexed etc
1485 $processingFolder = $this->getProcessingFolder();
1486 if ($processingFolder && $path == '/') {
1487 $processedFolderIdentifier = $this->processingFolder->getIdentifier();
1488 $processedFolderIdentifier = trim($processedFolderIdentifier, '/');
1489 if (isset($items[$processedFolderIdentifier])) {
1490 unset($items[$processedFolderIdentifier]);
1491 }
1492 }
1493 uksort($items, 'strnatcasecmp');
1494
1495 return $items;
1496 }
1497
1498 /**
1499 * Returns TRUE if the specified folder exists.
1500 *
1501 * @param $identifier
1502 * @return bool
1503 */
1504 public function hasFolder($identifier) {
1505 return $this->driver->folderExists($identifier);
1506 }
1507
1508 /**
1509 * Checks if the given file exists in the given folder
1510 *
1511 * @param string $folderName
1512 * @param t3lib_file_Folder $folder
1513 * @return boolean
1514 */
1515 public function hasFolderInFolder($folderName, t3lib_file_Folder $folder) {
1516 return $this->driver->folderExistsInFolder($folderName, $folder);
1517 }
1518
1519 /**
1520 * Creates a new folder.
1521 *
1522 * previously in t3lib_extFileFunc::func_newfolder()
1523 *
1524 * @param string $folderName the new folder name
1525 * @param t3lib_file_Folder $parentFolder The parent folder to create the new folder inside of
1526 * @return t3lib_file_Folder The new folder object
1527 */
1528 public function createFolder($folderName, t3lib_file_Folder $parentFolder) {
1529 if (!$this->checkFolderActionPermission('createFolder', $parentFolder)) {
1530 throw new t3lib_file_exception_InsufficientFolderWritePermissionsException('You are not allowed to create directories on this storage "' . $parentFolder->getIdentifier() . '"', 1323059807);
1531 }
1532
1533 if (!$this->driver->folderExists($parentFolder->getIdentifier())) {
1534 throw new InvalidArgumentException('Parent folder "' . $parentFolder->getIdentifier() . '" does not exist.', 1325689164);
1535 }
1536
1537 return $this->driver->createFolder($folderName, $parentFolder);
1538 }
1539
1540 /**
1541 * Returns the default folder where new files are stored if no other folder is given.
1542 *
1543 * @return t3lib_file_Folder
1544 */
1545 public function getDefaultFolder() {
1546 return $this->driver->getDefaultFolder();
1547 }
1548
1549 /**
1550 * @param string $identifier
1551 * @return t3lib_file_Folder
1552 */
1553 public function getFolder($identifier) {
1554 $folderObject = $this->driver->getFolder($identifier);
1555 if ($this->fileMounts && !$this->isWithinFileMountBoundaries($folderObject)) {
1556 throw new t3lib_file_exception_NotInMountPointException('Folder "' . $identifier . '" is not within your mount points.', 1330120649);
1557 } else {
1558 return $folderObject;
1559 }
1560 }
1561
1562 /**
1563 * Returns the folders on the root level of the storage
1564 * or the first mount point of this storage for this user
1565 *
1566 * @return t3lib_file_Folder
1567 */
1568 public function getRootLevelFolder() {
1569 if (count($this->fileMounts)) {
1570 $mount = reset($this->fileMounts);
1571 return $mount['folder'];
1572 } else {
1573 return $this->driver->getRootLevelFolder();
1574 }
1575 }
1576
1577 /**
1578 * Emits the configuration pre-processing signal
1579 *
1580 * @return void
1581 */
1582 protected function emitPreProcessConfigurationSignal() {
1583 $this->getSignalSlotDispatcher()->dispatch(
1584 't3lib_file_Storage',
1585 self::SIGNAL_PreProcessConfiguration,
1586 array($this)
1587 );
1588 }
1589
1590 /**
1591 * Emits the configuration post-processing signal
1592 *
1593 * @return void
1594 */
1595 protected function emitPostProcessConfigurationSignal() {
1596 $this->getSignalSlotDispatcher()->dispatch(
1597 't3lib_file_Storage',
1598 self::SIGNAL_PostProcessConfiguration,
1599 array($this)
1600 );
1601 }
1602
1603 /**
1604 * Emits file pre-copy signal
1605 *
1606 * @param t3lib_file_FileInterface $file
1607 * @param t3lib_file_Folder $targetFolder
1608 * @return void
1609 */
1610 protected function emitPreFileCopySignal(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder) {
1611 $this->getSignalSlotDispatcher()->dispatch(
1612 't3lib_file_Storage',
1613 self::SIGNAL_PreFileCopy,
1614 array($file, $targetFolder)
1615 );
1616 }
1617
1618 /**
1619 * Emits the file post-copy signal
1620 *
1621 * @param t3lib_file_FileInterface $file
1622 * @param t3lib_file_Folder $targetFolder
1623 * @return void
1624 */
1625 protected function emitPostFileCopySignal(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder) {
1626 $this->getSignalSlotDispatcher()->dispatch(
1627 't3lib_file_Storage',
1628 self::SIGNAL_PostFileCopy,
1629 array($file, $targetFolder)
1630 );
1631 }
1632
1633 /**
1634 * Emits the file pre-move signal
1635 *
1636 * @param t3lib_file_FileInterface $file
1637 * @param t3lib_file_Folder $targetFolder
1638 * @return void
1639 */
1640 protected function emitPreFileMoveSignal(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder) {
1641 $this->getSignalSlotDispatcher()->dispatch(
1642 't3lib_file_Storage',
1643 self::SIGNAL_PreFileMove,
1644 array($file, $targetFolder)
1645 );
1646 }
1647
1648 /**
1649 * Emits the file post-move signal
1650 *
1651 * @param t3lib_file_FileInterface $file
1652 * @param t3lib_file_Folder $targetFolder
1653 * @return void
1654 */
1655 protected function emitPostFileMoveSignal(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder) {
1656 $this->getSignalSlotDispatcher()->dispatch(
1657 't3lib_file_Storage',
1658 self::SIGNAL_PostFileMove,
1659 array($file, $targetFolder)
1660 );
1661 }
1662
1663 /**
1664 * Emits the file pre-rename signal
1665 *
1666 * @param t3lib_file_FileInterface $file
1667 * @param $targetFolder
1668 * @return void
1669 */
1670 protected function emitPreFileRenameSignal(t3lib_file_FileInterface $file, $targetFolder) {
1671 $this->getSignalSlotDispatcher()->dispatch(
1672 't3lib_file_Storage',
1673 self::SIGNAL_PreFileRename,
1674 array($file, $targetFolder)
1675 );
1676 }
1677
1678 /**
1679 * Emits the file post-rename signal
1680 *
1681 * @param t3lib_file_FileInterface $file
1682 * @param $targetFolder
1683 * @return void
1684 */
1685 protected function emitPostFileRenameSignal(t3lib_file_FileInterface $file, $targetFolder) {
1686 $this->getSignalSlotDispatcher()->dispatch(
1687 't3lib_file_Storage',
1688 self::SIGNAL_PostFileRename,
1689 array($file, $targetFolder)
1690 );
1691 }
1692
1693 /**
1694 * Emits the file pre-replace signal
1695 *
1696 * @param t3lib_file_FileInterface $file
1697 * @param $localFilePath
1698 * @return void
1699 */
1700 protected function emitPreFileReplaceSignal(t3lib_file_FileInterface $file, $localFilePath) {
1701 $this->getSignalSlotDispatcher()->dispatch(
1702 't3lib_file_Storage',
1703 self::SIGNAL_PreFileReplace,
1704 array($file, $localFilePath)
1705 );
1706 }
1707
1708 /**
1709 * Emits the file post-replace signal
1710 *
1711 * @param t3lib_file_FileInterface $file
1712 * @param $localFilePath
1713 * @return void
1714 */
1715 protected function emitPostFileReplaceSignal(t3lib_file_FileInterface $file, $localFilePath) {
1716 $this->getSignalSlotDispatcher()->dispatch(
1717 't3lib_file_Storage',
1718 self::SIGNAL_PostFileReplace,
1719 array($file, $localFilePath)
1720 );
1721 }
1722
1723 /**
1724 * Emits the file pre-deletion signal
1725 *
1726 * @param t3lib_file_FileInterface $file
1727 * @return void
1728 */
1729 protected function emitPreFileDeleteSignal(t3lib_file_FileInterface $file) {
1730 $this->getSignalSlotDispatcher()->dispatch(
1731 't3lib_file_Storage',
1732 self::SIGNAL_PreFileDelete,
1733 array($file)
1734 );
1735 }
1736
1737 /**
1738 * Emits the file post-deletion signal
1739 *
1740 * @param t3lib_file_FileInterface $file
1741 * @return void
1742 */
1743 protected function emitPostFileDeleteSignal(t3lib_file_FileInterface $file) {
1744 $this->getSignalSlotDispatcher()->dispatch(
1745 't3lib_file_Storage',
1746 self::SIGNAL_PostFileDelete,
1747 array($file)
1748 );
1749 }
1750
1751 /**
1752 * Emits the folder pre-copy signal
1753 *
1754 * @param t3lib_File_Folder $folder
1755 * @param t3lib_file_Folder $targetFolder
1756 * @param $newName
1757 * @return void
1758 */
1759 protected function emitPreFolderCopySignal(t3lib_File_Folder $folder, t3lib_file_Folder $targetFolder, $newName) {
1760 $this->getSignalSlotDispatcher()->dispatch(
1761 't3lib_File_Storage',
1762 self::SIGNAL_PreFolderCopy,
1763 array($folder, $targetFolder)
1764 );
1765 }
1766
1767 /**
1768 * Emits the folder post-copy signal
1769 *
1770 * @param t3lib_File_Folder $folder
1771 * @param t3lib_file_Folder $targetFolder
1772 * @param $newName
1773 * @return void
1774 */
1775 protected function emitPostFolderCopySignal(t3lib_File_Folder $folder, t3lib_file_Folder $targetFolder, $newName) {
1776 $this->getSignalSlotDispatcher()->dispatch(
1777 't3lib_File_Storage',
1778 self::SIGNAL_PostFolderCopy,
1779 array($folder, $targetFolder)
1780 );
1781 }
1782
1783 /**
1784 * Emits the folder pre-move signal
1785 *
1786 * @param t3lib_File_Folder $folder
1787 * @param t3lib_file_Folder $targetFolder
1788 * @param $newName
1789 * @return void
1790 */
1791 protected function emitPreFolderMoveSignal(t3lib_File_Folder $folder, t3lib_file_Folder $targetFolder, $newName) {
1792 $this->getSignalSlotDispatcher()->dispatch(
1793 't3lib_File_Storage',
1794 self::SIGNAL_PreFolderMove,
1795 array($folder, $targetFolder)
1796 );
1797 }
1798
1799 /**
1800 * Emits the folder post-move signal
1801 *
1802 * @param t3lib_File_Folder $folder
1803 * @param t3lib_file_Folder $targetFolder
1804 * @param $newName
1805 * @return void
1806 */
1807 protected function emitPostFolderMoveSignal(t3lib_File_Folder $folder, t3lib_file_Folder $targetFolder, $newName) {
1808 $this->getSignalSlotDispatcher()->dispatch(
1809 't3lib_File_Storage',
1810 self::SIGNAL_PostFolderMove,
1811 array($folder, $targetFolder)
1812 );
1813 }
1814
1815 /**
1816 * Emits the folder pre-rename signal
1817 *
1818 * @param t3lib_File_Folder $folder
1819 * @param $newName
1820 * @return void
1821 */
1822 protected function emitPreFolderRenameSignal(t3lib_File_Folder $folder, $newName) {
1823 $this->getSignalSlotDispatcher()->dispatch(
1824 't3lib_File_Storage',
1825 self::SIGNAL_PreFolderRename,
1826 array($folder, $newName)
1827 );
1828 }
1829
1830 /**
1831 * Emits the folder post-rename signal
1832 *
1833 * @param t3lib_File_Folder $folder
1834 * @param $newName
1835 * @return void
1836 */
1837 protected function emitPostFolderRenameSignal(t3lib_File_Folder $folder, $newName) {
1838 $this->getSignalSlotDispatcher()->dispatch(
1839 't3lib_File_Storage',
1840 self::SIGNAL_PostFolderRename,
1841 array($folder, $newName)
1842 );
1843 }
1844
1845 /**
1846 * Emits the folder pre-deletion signal
1847 *
1848 * @param t3lib_File_Folder $folder
1849 * @return void
1850 */
1851 protected function emitPreFolderDeleteSignal(t3lib_File_Folder $folder) {
1852 $this->getSignalSlotDispatcher()->dispatch(
1853 't3lib_File_Storage',
1854 self::SIGNAL_PreFolderDelete,
1855 array($folder)
1856 );
1857 }
1858
1859 /**
1860 * Emits folder postdeletion signal.
1861 *
1862 * @param t3lib_File_Folder $folder
1863 * @return void
1864 */
1865 protected function emitPostFolderDeleteSignal(t3lib_File_Folder $folder) {
1866 $this->getSignalSlotDispatcher()->dispatch(
1867 't3lib_File_Storage',
1868 self::SIGNAL_PostFolderDelete,
1869 array($folder)
1870 );
1871 }
1872
1873
1874 /**
1875 * Emits file pre-processing signal.
1876 *
1877 * @param t3lib_file_ProcessedFile $processedFile
1878 * @param t3lib_file_FileInterface $file
1879 * @param string $context
1880 * @param array $configuration
1881 */
1882 protected function emitPreFileProcess(t3lib_file_ProcessedFile $processedFile, t3lib_file_FileInterface $file, $context, array $configuration = array()) {
1883 $this->getSignalSlotDispatcher()->dispatch(
1884 't3lib_file_Storage',
1885 self::SIGNAL_PreFileProcess,
1886 array($this, $this->driver, $processedFile, $file, $context, $configuration)
1887 );
1888 }
1889
1890 /**
1891 * Emits file post-processing signal.
1892 *
1893 * @param t3lib_file_ProcessedFile $processedFile
1894 * @param t3lib_file_FileInterface $file
1895 * @param $context
1896 * @param array $configuration
1897 */
1898 protected function emitPostFileProcess(t3lib_file_ProcessedFile $processedFile, t3lib_file_FileInterface $file, $context, array $configuration = array()) {
1899 $this->getSignalSlotDispatcher()->dispatch(
1900 't3lib_file_Storage',
1901 self::SIGNAL_PostFileProcess,
1902 array($this, $this->driver, $processedFile, $file, $context, $configuration)
1903 );
1904 }
1905
1906
1907
1908 /**
1909 * Returns the destination path/fileName of a unique fileName/foldername in that path.
1910 * If $theFile exists in $theDest (directory) the file have numbers appended up to $this->maxNumber. Hereafter a unique string will be appended.
1911 * This function is used by fx. TCEmain when files are attached to records and needs to be uniquely named in the uploads/* folders
1912 *
1913 * @param t3lib_file_Folder $folder
1914 * @param string $theFile The input fileName to check
1915 * @param boolean $dontCheckForUnique If set the fileName is returned with the path prepended without checking whether it already existed!
1916 * @return string A unique fileName inside $folder, based on $theFile.
1917 * @see t3lib_basicFileFunc::getUniqueName()
1918 */
1919 // TODO check if this should be moved back to t3lib_file_Folder
1920 protected function getUniqueName(t3lib_file_Folder $folder, $theFile, $dontCheckForUnique = FALSE) {
1921 static $maxNumber = 99, $uniqueNamePrefix = '';
1922
1923 // Fetches info about path, name, extention of $theFile
1924 $origFileInfo = t3lib_div::split_fileref($theFile);
1925 // Adds prefix
1926 if ($uniqueNamePrefix) {
1927 $origFileInfo['file'] = $uniqueNamePrefix . $origFileInfo['file'];
1928 $origFileInfo['filebody'] = $uniqueNamePrefix . $origFileInfo['filebody'];
1929 }
1930
1931 // Check if the file exists and if not - return the fileName...
1932 $fileInfo = $origFileInfo;
1933 // The destinations file
1934 $theDestFile = $fileInfo['file'];
1935 // If the file does NOT exist we return this fileName
1936 if (!$this->driver->fileExistsInFolder($theDestFile, $folder) || $dontCheckForUnique) {
1937 return $theDestFile;
1938 }
1939
1940 // Well the fileName in its pure form existed. Now we try to append
1941 // numbers / unique-strings and see if we can find an available fileName
1942
1943 // This removes _xx if appended to the file
1944 $theTempFileBody = preg_replace('/_[0-9][0-9]$/', '', $origFileInfo['filebody']);
1945 $theOrigExt = $origFileInfo['realFileext'] ? '.' . $origFileInfo['realFileext'] : '';
1946
1947 for ($a = 1; $a <= ($maxNumber + 1); $a++) {
1948 // First we try to append numbers
1949 if ($a <= $maxNumber) {
1950 $insert = '_' . sprintf('%02d', $a);
1951 // .. then we try unique-strings...
1952 } else {
1953 // TODO remove constant 6
1954 $insert = '_' . substr(md5(uniqId('')), 0, 6);
1955 }
1956 $theTestFile = $theTempFileBody . $insert . $theOrigExt;
1957 // The destinations file
1958 $theDestFile = $theTestFile;
1959 // If the file does NOT exist we return this fileName
1960 if (!$this->driver->fileExistsInFolder($theDestFile, $folder)) {
1961 return $theDestFile;
1962 }
1963 }
1964
1965 throw new RuntimeException('Last possible name "' . $theDestFile . '" is already taken.', 1325194291);
1966 }
1967
1968 /**
1969 * Get the SignalSlot dispatcher
1970 *
1971 * @return Tx_Extbase_SignalSlot_Dispatcher
1972 */
1973 protected function getSignalSlotDispatcher() {
1974 if (!isset($this->signalSlotDispatcher)) {
1975 $this->signalSlotDispatcher = $this->getObjectManager()->get('Tx_Extbase_SignalSlot_Dispatcher');
1976 }
1977 return $this->signalSlotDispatcher;
1978 }
1979
1980 /**
1981 * Get the ObjectManager
1982 *
1983 * @return Tx_Extbase_Object_ObjectManager
1984 */
1985 protected function getObjectManager() {
1986 return t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
1987 }
1988
1989 /**
1990 * @return t3lib_file_Factory
1991 */
1992 protected function getFileFactory() {
1993 return t3lib_div::makeInstance('t3lib_file_Factory');
1994 }
1995
1996 /**
1997 * @return t3lib_file_Service_FileProcessingService
1998 */
1999 protected function getFileProcessingService() {
2000 if (!$this->fileProcessingService) {
2001 $this->fileProcessingService = t3lib_div::makeInstance(
2002 't3lib_file_Service_FileProcessingService',
2003 $this,
2004 $this->driver
2005 );
2006 }
2007 return $this->fileProcessingService;
2008 }
2009
2010 /**
2011 * Getter function to return the folder where the files can
2012 * be processed. does not check for access rights here
2013 * @todo check if we need to implement "is writable" capability
2014 *
2015 * @return t3lib_file_Folder the processing folder, can be empty as well, if the storage doesn't have a processing folder
2016 */
2017 public function getProcessingFolder() {
2018 if (!isset($this->processingFolder)) {
2019 $processingFolder = self::DEFAULT_ProcessingFolder;
2020
2021 if (!empty($this->storageRecord['processingfolder'])) {
2022 $processingFolder = $this->storageRecord['processingfolder'];
2023 }
2024
2025 $processingFolder = trim($processingFolder, '/');
2026
2027 // @todo: does not resolve deeplinked folders like typo3temp/_processed_
2028 if ($this->driver->folderExists($processingFolder) === FALSE) {
2029 $this->processingFolder = $this->driver->createFolder(
2030 $processingFolder,
2031 $this->driver->getRootLevelFolder()
2032 );
2033 } else {
2034 $this->processingFolder = $this->driver->getFolder($processingFolder);
2035 }
2036 }
2037
2038 return $this->processingFolder;
2039 }
2040 }
2041
2042 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/file/Storage.php'])) {
2043 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/file/Storage.php']);
2044 }
2045
2046 ?>