[TASK] Clean up and fix unit tests for FAL
[Packages/TYPO3.CMS.git] / t3lib / file / Driver / AbstractDriver.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Ingmar Schlecht <ingmar.schlecht@typo3.org>
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 * An abstract implementation of a storage driver.
31 *
32 * @author Ingmar Schlecht <ingmar.schlecht@typo3.org>
33 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
34 * @package TYPO3
35 * @subpackage t3lib
36 */
37 abstract class t3lib_file_Driver_AbstractDriver {
38
39 /**
40 * The mount object this driver instance belongs to
41 *
42 * @var t3lib_file_Storage
43 */
44 protected $storage;
45
46 /**
47 * A list of all supported hash algorithms, written all lower case and
48 * without any dashes etc. (e.g. sha1 instead of SHA-1)
49 * Be sure to set this in inherited classes!
50 *
51 * @var array
52 */
53 protected $supportedHashAlgorithms = array();
54
55 /**
56 * The storage folder that forms the root of this FS tree
57 *
58 * @var t3lib_file_Folder
59 */
60 protected $rootLevelFolder;
61
62 /**
63 * The default folder new files should be put into.
64 *
65 * @var t3lib_file_Folder
66 */
67 protected $defaultLevelFolder;
68
69 /**
70 * The configuration of this driver
71 *
72 * @var array
73 */
74 protected $configuration = array();
75
76 /**
77 * The callback method to handle the files when listing folder contents
78 *
79 * @var string
80 */
81 protected $fileListCallbackMethod = 'getFileList_itemCallback';
82
83 /**
84 * The callback method to handle the folders when listing folder contents
85 *
86 * @var string
87 */
88 protected $folderListCallbackMethod = 'getFolderList_itemCallback';
89
90 /**
91 * Creates this object.
92 *
93 * @param array $configuration
94 */
95 public function __construct(array $configuration = array()) {
96 $this->configuration = $configuration;
97 }
98
99 /**
100 * Initializes this object. This is called by the storage after the driver
101 * has been attached.
102 *
103 * @return void
104 */
105 abstract public function initialize();
106
107 /**
108 * Checks a fileName for validity. This could be overriden in concrete
109 * drivers if they have different file naming rules.
110 *
111 * @param string $fileName
112 * @return boolean TRUE if file name is valid
113 */
114 public function isValidFilename($fileName) {
115 if (strpos($fileName, '/') !== FALSE) {
116 return FALSE;
117 }
118 if (!preg_match('/^[[:alnum:][:blank:]\.-_]*$/iu', $fileName)) {
119 return FALSE;
120 }
121
122 return TRUE;
123 }
124
125 /**
126 * Sets the storage object that works with this driver
127 *
128 * @param t3lib_file_Storage $storage
129 * @return t3lib_file_Driver_AbstractDriver
130 */
131 public function setStorage(t3lib_file_Storage $storage) {
132 $this->storage = $storage;
133 return $this;
134 }
135
136 /**
137 * Checks if a configuration is valid for this driver.
138 * Throws an exception if a configuration will not work.
139 *
140 * @abstract
141 * @param array $configuration
142 * @return void
143 */
144 abstract public static function verifyConfiguration(array $configuration);
145
146 /**
147 * processes the configuration, should be overridden by subclasses
148 *
149 * @return void
150 */
151 abstract public function processConfiguration();
152
153 /**
154 * Returns the name of a file/folder based on its identifier.
155 *
156 * @param string $identifier
157 * @return string
158 */
159 protected function getNameFromIdentifier($identifier) {
160 return basename($identifier);
161 }
162
163 /**
164 * Generic handler method for directory listings - gluing together the
165 * listing items is done
166 *
167 * @param string $path
168 * @param integer $start
169 * @param integer $numberOfItems
170 * @param array $filterMethods The filter methods used to filter the directory items
171 * @param string $itemHandlerMethod
172 * @param array $itemRows
173 * @return array
174 */
175 protected function getDirectoryItemList($path, $start, $numberOfItems, $filterMethods, $itemHandlerMethod, $itemRows = array()) {
176 // This is not abstract because PHPUnit cannot mock abstract protected/private methods
177 }
178
179 /*******************
180 * CAPABILITIES
181 *******************/
182
183 /**
184 * The capabilities of this driver. See Storage::CAPABILITY_* constants for possible values. This value should be set
185 * in the constructor of derived classes.
186 *
187 * @var integer
188 */
189 protected $capabilities = 0;
190
191 /**
192 * Returns the capabilities of this driver.
193 *
194 * @return integer
195 * @see Storage::CAPABILITY_* constants
196 */
197 public function getCapabilities() {
198 return $this->capabilities;
199 }
200
201 /**
202 * Returns TRUE if this driver has the given capability.
203 *
204 * @param int $capability A capability, as defined in a CAPABILITY_* constant
205 * @return boolean
206 */
207 public function hasCapability($capability) {
208 return ($this->capabilities & $capability == $capability);
209 }
210
211
212 /*******************
213 * FILE FUNCTIONS
214 *******************/
215
216 /**
217 * Returns a temporary path for a given file, including the file extension.
218 *
219 * @param t3lib_file_FileInterface $file
220 * @return string
221 */
222 protected function getTemporaryPathForFile(t3lib_file_FileInterface $file) {
223 return t3lib_div::tempnam('fal-tempfile-') . '.' . $file->getExtension();
224 // @todo: we need to remove the temporary file again
225 }
226
227 /**
228 * Returns the public URL to a file.
229 *
230 * @abstract
231 * @param t3lib_file_ResourceInterface $resource
232 * @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)
233 * @return string
234 */
235 abstract public function getPublicUrl(t3lib_file_ResourceInterface $resource, $relativeToCurrentScript = FALSE);
236
237 /**
238 * Returns a list of all hashing algorithms this Storage supports.
239 *
240 * @return array
241 */
242 public function getSupportedHashAlgorithms() {
243 return $this->supportedHashAlgorithms;
244 }
245
246 /**
247 * Creates a (cryptographic) hash for a file.
248 *
249 * @abstract
250 * @param t3lib_file_FileInterface $file
251 * @param string $hashAlgorithm The hash algorithm to use
252 * @return string
253 * TODO switch parameter order?
254 */
255 abstract public function hash(t3lib_file_FileInterface $file, $hashAlgorithm);
256
257 /**
258 * Creates a new file and returns the matching file object for it.
259 *
260 * @abstract
261 * @param string $fileName
262 * @param t3lib_file_Folder $parentFolder
263 * @return t3lib_file_File
264 */
265 abstract public function createFile($fileName, t3lib_file_Folder $parentFolder);
266
267 /**
268 * Returns the contents of a file. Beware that this requires to load the
269 * complete file into memory and also may require fetching the file from an
270 * external location. So this might be an expensive operation (both in terms
271 * of processing resources and money) for large files.
272 *
273 * @param t3lib_file_FileInterface $file
274 * @return string The file contents
275 */
276 abstract public function getFileContents(t3lib_file_FileInterface $file);
277
278 /**
279 * Sets the contents of a file to the specified value.
280 *
281 * @param t3lib_file_FileInterface $file
282 * @param string $contents
283 * @return integer The number of bytes written to the file
284 * @throws RuntimeException if the operation failed
285 */
286 abstract public function setFileContents(t3lib_file_FileInterface $file, $contents);
287
288 /**
289 * Adds a file from the local server hard disk to a given path in TYPO3s virtual file system.
290 *
291 * This assumes that the local file exists, so no further check is done here!
292 *
293 * @param string $localFilePath
294 * @param t3lib_file_Folder $targetFolder
295 * @param string $fileName The name to add the file under
296 * @param t3lib_file_AbstractFile $updateFileObject Optional file object to update (instead of creating a new object). With this parameter, this function can be used to "populate" a dummy file object with a real file underneath.
297 * @return t3lib_file_FileInterface
298 */
299 abstract public function addFile($localFilePath, t3lib_file_Folder $targetFolder, $fileName, t3lib_file_AbstractFile $updateFileObject = NULL);
300
301 /**
302 * Checks if a resource exists - does not care for the type (file or folder).
303 *
304 * @param $identifier
305 * @return boolean
306 */
307 abstract public function resourceExists($identifier);
308
309 /**
310 * Checks if a file exists.
311 *
312 * @abstract
313 * @param string $identifier
314 * @return boolean
315 */
316 abstract public function fileExists($identifier);
317
318 /**
319 * Checks if a file inside a storage folder exists.
320 *
321 * @abstract
322 * @param string $fileName
323 * @param t3lib_file_Folder $folder
324 * @return boolean
325 */
326 abstract public function fileExistsInFolder($fileName, t3lib_file_Folder $folder);
327
328 /**
329 * Returns a (local copy of) a file for processing it. When changing the
330 * file, you have to take care of replacing the current version yourself!
331 *
332 * @abstract
333 * @param t3lib_file_FileInterface $file
334 * @param bool $writable Set this to FALSE if you only need the file for read operations. This might speed up things, e.g. by using a cached local version. Never modify the file if you have set this flag!
335 * @return string The path to the file on the local disk
336 */
337 // TODO decide if this should return a file handle object
338 abstract public function getFileForLocalProcessing(t3lib_file_FileInterface $file, $writable = TRUE);
339
340 /**
341 * Returns the permissions of a file as an array (keys r, w) of boolean flags
342 *
343 * @abstract
344 * @param t3lib_file_FileInterface $file
345 * @return array
346 */
347 abstract public function getFilePermissions(t3lib_file_FileInterface $file);
348
349 /**
350 * Returns the permissions of a folder as an array (keys r, w) of boolean flags
351 *
352 * @abstract
353 * @param t3lib_file_Folder $folder
354 * @return array
355 */
356 abstract public function getFolderPermissions(t3lib_file_Folder $folder);
357
358 /**
359 * Renames a file
360 *
361 * @abstract
362 * @param t3lib_file_FileInterface $file
363 * @param string $newName
364 * @return string The new identifier of the file if the operation succeeds
365 * @throws RuntimeException if renaming the file failed
366 */
367 abstract public function renameFile(t3lib_file_FileInterface $file, $newName);
368
369 /**
370 * Replaces the contents (and file-specific metadata) of a file object with a local file.
371 *
372 * @abstract
373 * @param t3lib_file_AbstractFile $file
374 * @param string $localFilePath
375 * @return boolean
376 */
377 abstract public function replaceFile(t3lib_file_AbstractFile $file, $localFilePath);
378
379 /**
380 * Returns information about a file for a given file identifier.
381 *
382 * @param string $identifier The (relative) path to the file.
383 * @return array
384 */
385 abstract public function getFileInfoByIdentifier($identifier);
386
387 /**
388 * Returns information about a file for a given file object.
389 *
390 * @param t3lib_file_FileInterface $file
391 * @return array
392 */
393 public function getFileInfo(t3lib_file_FileInterface $file) {
394 return $this->getFileInfoByIdentifier($file->getIdentifier());
395 }
396
397 /**
398 * Returns a file object by its identifier.
399 *
400 * @param string $identifier
401 * @return t3lib_file_FileInterface
402 */
403 public function getFile($identifier) {
404 $fileObject = NULL;
405
406 if (!$this->fileExists($identifier)) {
407 throw new t3lib_file_exception_FileDoesNotExistException();
408 }
409 $fileInfo = $this->getFileInfoByIdentifier($identifier);
410 $fileObject = $this->getFileObject($fileInfo);
411
412 return $fileObject;
413 }
414
415 /**
416 * Creates a file object from a given file data array
417 *
418 * @param array $fileData
419 * @return t3lib_file_File
420 */
421 protected function getFileObject(array $fileData) {
422 $fileObject = t3lib_file_Factory::getInstance()->createFileObject($fileData);
423
424 return $fileObject;
425 }
426
427 /**
428 * Returns a folder by its identifier.
429 *
430 * @param string $identifier
431 * @return t3lib_file_Folder
432 */
433 public function getFolder($identifier) {
434 $name = $this->getNameFromIdentifier($identifier);
435
436 return t3lib_file_Factory::getInstance()->createFolderObject(
437 $this->storage,
438 $identifier,
439 $name
440 );
441 }
442
443 /**
444 * Returns a folder within the given folder. Use this method instead of doing your own string manipulation magic
445 * on the identifiers because non-hierarchical storages might fail otherwise.
446 *
447 * @param $name
448 * @param t3lib_file_Folder $parentFolder
449 * @return t3lib_file_Folder
450 */
451 abstract public function getFolderInFolder($name, t3lib_file_Folder $parentFolder);
452
453 /**
454 * Applies a set of filter methods to a file name to find out if it should be used or not. This is e.g. used by
455 * directory listings.
456 *
457 * @param string $itemName
458 * @param string $itemIdentifier
459 * @param string $parentIdentifier
460 * @param array $filterMethods
461 * @return bool
462 */
463 protected function applyFilterMethodsToDirectoryItem($itemName, $itemIdentifier, $parentIdentifier, array $filterMethods) {
464 foreach ($filterMethods as $filter) {
465 if (is_array($filter)) {
466 $result = call_user_func($filter, $itemName, $itemIdentifier, $parentIdentifier, $this);
467
468 // We have to use -1 as the „don't include“ return value, as call_user_func() will return FALSE
469 // If calling the method succeeded and thus we can't use that as a return value.
470 if ($result === -1) {
471 return FALSE;
472 } elseif ($result === FALSE) {
473 throw new RuntimeException('Could not apply file/folder name filter ' . $filter[0] . '::' . $filter[1]);
474 }
475 }
476 }
477
478 return TRUE;
479 }
480
481 /**
482 * Returns a list of files inside the specified path
483 *
484 * @param string $path
485 * @param integer $start The position to start the listing; if not set, start from the beginning
486 * @param integer $numberOfItems The number of items to list; if not set, return all items
487 * @param array $filenameFilterCallbacks The method callbacks to use for filtering the items
488 * @param array $fileData Two-dimensional, identifier-indexed array of file index records from the database
489 * @return array
490 */
491 // TODO add unit tests
492 public function getFileList($path, $start = 0, $numberOfItems = 0, array $filenameFilterCallbacks = array(), $fileData = array()) {
493 return $this->getDirectoryItemList($path, $start, $numberOfItems, $filenameFilterCallbacks, $this->fileListCallbackMethod, $fileData);
494 }
495
496 /**
497 * Copies a file to a temporary path and returns that path.
498 *
499 * @abstract
500 * @param t3lib_file_FileInterface $file
501 * @return string The temporary path
502 */
503 abstract public function copyFileToTemporaryPath(t3lib_file_FileInterface $file);
504
505 /**
506 * Moves a file *within* the current storage.
507 * Note that this is only about an intra-storage move action, where a file is just
508 * moved to another folder in the same storage.
509 *
510 * @param t3lib_file_FileInterface $file
511 * @param t3lib_file_Folder $targetFolder
512 * @param string $fileName
513 * @return string The new identifier of the file
514 */
515 abstract public function moveFileWithinStorage(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder, $fileName);
516
517 /**
518 * Copies a file *within* the current storage.
519 * Note that this is only about an intra-storage copy action, where a file is just
520 * copied to another folder in the same storage.
521 *
522 * @param t3lib_file_FileInterface $file
523 * @param t3lib_file_Folder $targetFolder
524 * @param string $fileName
525 * @return t3lib_file_FileInterface The new (copied) file object.
526 */
527 abstract public function copyFileWithinStorage(t3lib_file_FileInterface $file, t3lib_file_Folder $targetFolder, $fileName);
528
529 /**
530 * Folder equivalent to moveFileWithinStorage().
531 *
532 * @param t3lib_file_Folder $folderToMove
533 * @param t3lib_file_Folder $targetFolder
534 * @param string $newFolderName
535 * @return array A map of old to new file identifiers
536 */
537 abstract public function moveFolderWithinStorage(t3lib_file_Folder $folderToMove, t3lib_file_Folder $targetFolder, $newFolderName);
538
539 /**
540 * Folder equivalent to copyFileWithinStorage().
541 *
542 * @param t3lib_file_Folder $folderToMove
543 * @param t3lib_file_Folder $targetFolder
544 * @param string $newFileName
545 * @return boolean
546 */
547 abstract public function copyFolderWithinStorage(t3lib_file_Folder $folderToMove, t3lib_file_Folder $targetFolder, $newFileName);
548
549 /**
550 * Removes a file from this storage. This does not check if the file is
551 * still used or if it is a bad idea to delete it for some other reason
552 * this has to be taken care of in the upper layers (e.g. the Storage)!
553 *
554 * @abstract
555 * @param t3lib_file_FileInterface $file
556 * @return boolean TRUE if deleting the file succeeded
557 */
558 abstract public function deleteFile(t3lib_file_FileInterface $file);
559
560 /**
561 * Removes a folder from this storage.
562 *
563 * @param t3lib_file_Folder $folder
564 * @param boolean $deleteRecursively
565 * @return boolean
566 */
567 abstract public function deleteFolder(t3lib_file_Folder $folder, $deleteRecursively = FALSE);
568
569 /**
570 * Adds a file at the specified location. This should only be used internally.
571 *
572 * @abstract
573 * @param string $localFilePath
574 * @param t3lib_file_Folder $targetFolder
575 * @param string $targetFileName
576 * @return string The new identifier of the file
577 */
578 // TODO check if this is still necessary if we move more logic to the storage
579 abstract public function addFileRaw($localFilePath, t3lib_file_Folder $targetFolder, $targetFileName);
580
581 /**
582 * Deletes a file without access and usage checks.
583 * This should only be used internally.
584 *
585 * This accepts an identifier instead of an object because we might want to
586 * delete files that have no object associated with (or we don't want to
587 * create an object for) them - e.g. when moving a file to another storage.
588 *
589 * @abstract
590 * @param string $identifier
591 * @return boolean TRUE if removing the file succeeded
592 */
593 abstract public function deleteFileRaw($identifier);
594
595 /*******************
596 * FOLDER FUNCTIONS
597 *******************/
598
599 /**
600 * Returns the root level folder of the storage.
601 *
602 * @abstract
603 * @return t3lib_file_Folder
604 */
605 abstract public function getRootLevelFolder();
606
607 /**
608 * Returns the default folder new files should be put into.
609 *
610 * @abstract
611 * @return t3lib_file_Folder
612 */
613 abstract public function getDefaultFolder();
614
615 /**
616 * Creates a folder.
617 *
618 * @param string $newFolderName
619 * @param t3lib_file_Folder $parentFolder
620 * @return t3lib_file_Folder The new (created) folder object
621 */
622 abstract public function createFolder($newFolderName, t3lib_file_Folder $parentFolder);
623
624 /**
625 * Returns a list of all folders in a given path
626 *
627 * @param string $path
628 * @param integer $start The position to start the listing; if not set, start from the beginning
629 * @param integer $numberOfItems The number of items to list; if not set, return all items
630 * @param array $foldernameFilterCallbacks The method callbacks to use for filtering the items
631 * @return array
632 */
633 public function getFolderList($path, $start = 0, $numberOfItems = 0, array $foldernameFilterCallbacks = array()) {
634 return $this->getDirectoryItemList($path, $start, $numberOfItems, $foldernameFilterCallbacks, $this->folderListCallbackMethod);
635 }
636
637 /**
638 * Checks if a folder exists
639 *
640 * @abstract
641 * @param string $identifier
642 * @return boolean
643 */
644 abstract public function folderExists($identifier);
645
646 /**
647 * Checks if a file inside a storage folder exists.
648 *
649 * @abstract
650 * @param string $folderName
651 * @param t3lib_file_Folder $folder
652 * @return boolean
653 */
654 abstract public function folderExistsInFolder($folderName, t3lib_file_Folder $folder);
655
656 /**
657 * Renames a folder in this storage.
658 *
659 * @param t3lib_file_Folder $folder
660 * @param string $newName The target path (including the file name!)
661 * @return array A map of old to new file identifiers
662 * @throws RuntimeException if renaming the folder failed
663 */
664 abstract public function renameFolder(t3lib_file_Folder $folder, $newName);
665
666 /**
667 * Checks if a given object or identifier is within a container, e.g. if
668 * a file or folder is within another folder.
669 * This can e.g. be used to check for webmounts.
670 *
671 * @abstract
672 * @param t3lib_file_Folder $container
673 * @param mixed $content An object or an identifier to check
674 * @return boolean TRUE if $content is within $container
675 */
676 abstract public function isWithin(t3lib_file_Folder $container, $content);
677
678 /**
679 * Checks if a folder contains files and (if supported) other folders.
680 *
681 * @param t3lib_file_Folder $folder
682 * @return boolean TRUE if there are no files and folders within $folder
683 */
684 abstract public function isFolderEmpty(t3lib_file_Folder $folder);
685 }
686
687 ?>