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