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