Completed
Push — master ( 3c9969...e7a0ae )
by Cedric
01:45
created

FlysystemDriver::hash()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 21
ccs 0
cts 3
cp 0
rs 9.0534
cc 4
eloc 16
nc 4
nop 2
crap 20
1
<?php
2
3
namespace CedricZiel\FalFlysystem\Fal;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2016 Cedric Ziel <[email protected]>
9
 *
10
 *  All rights reserved
11
 *
12
 *  This script is part of the TYPO3 project. The TYPO3 project is
13
 *  free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 3 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  The GNU General Public License can be found at
19
 *  http://www.gnu.org/copyleft/gpl.html.
20
 *
21
 *  This script is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  This copyright notice MUST APPEAR in all copies of the script!
27
 ***************************************************************/
28
29
use League\Flysystem\Adapter\Local;
30
use League\Flysystem\AdapterInterface;
31
use League\Flysystem\Config;
32
use League\Flysystem\FilesystemInterface;
33
34
/**
35
 * Class FlysystemDriver
36
 * @package CedricZiel\FalFlysystem\Fal
37
 */
38
abstract class FlysystemDriver extends AbstractHierarchicalFilesystemDriver
39
{
40
    /**
41
     * @var FilesystemInterface
42
     */
43 51
    protected $filesystem;
44
45 51
    /**
46
     * @var AdapterInterface
47 51
     */
48 17
    protected $adapter;
49 51
50 51
    /**
51 51
     * @var string
52
     */
53
    protected $entryPath;
54
55
    /**
56
     * FlysystemDriver constructor.
57
     * @param array $configuration
58
     */
59
    public function __construct(array $configuration = [])
60
    {
61
        parent::__construct($configuration);
62
        // The capabilities default of this driver. See CAPABILITY_* constants for possible values
63
        $this->capabilities =
64
            ResourceStorage::CAPABILITY_BROWSABLE
65
            | ResourceStorage::CAPABILITY_PUBLIC
66
            | ResourceStorage::CAPABILITY_WRITABLE;
67
    }
68
69
    /**
70
     * Processes the configuration for this driver.
71
     * @return void
72
     */
73
    public function processConfiguration()
74
    {
75
        $this->entryPath = $this->configuration['path'];
76
    }
77
78
    /**
79
     * Merges the capabilities merged by the user at the storage
80
     * configuration into the actual capabilities of the driver
81
     * and returns the result.
82
     *
83
     * @param int $capabilities
84
     * @return int
85
     */
86
    public function mergeConfigurationCapabilities($capabilities)
87
    {
88
        $this->capabilities &= $capabilities;
89
        return $this->capabilities;
90 3
    }
91
92 3
    /**
93 3
     * Returns the identifier of the root level folder of the storage.
94 3
     *
95 3
     * @return string
96 2
     */
97 3
    public function getRootLevelFolder()
98
    {
99
        return '/';
100
    }
101
102
    /**
103
     * Returns the identifier of the default folder new files should be put into.
104
     *
105
     * @return string
106 6
     */
107
    public function getDefaultFolder()
108 6
    {
109
        $identifier = '/user_upload/';
110
        $createFolder = !$this->folderExists($identifier);
111 6
        if (true === $createFolder) {
112
            $identifier = $this->createFolder('user_upload');
113
        }
114
        return $identifier;
115
    }
116
117
    /**
118
     * Checks if a folder exists.
119
     *
120
     * @param string $folderIdentifier
121
     * @return bool
122
     */
123
    public function folderExists($folderIdentifier)
124 9
    {
125
        $normalizedIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
126 9
        $normalizedIdentifier = ltrim(rtrim($normalizedIdentifier, '/'), '/');
127 9
128
        if ('/' === $folderIdentifier) {
129 9
            return true;
130 9
        } else {
131 9
            return (
132
                $this->filesystem->has($normalizedIdentifier)
133 9
                && $this->filesystem->get($normalizedIdentifier)->isDir()
134
            );
135
        }
136
    }
137
138
    /**
139
     * Creates a folder, within a parent folder.
140
     * If no parent folder is given, a root level folder will be created
141
     *
142
     * @param string $newFolderName
143
     * @param string $parentFolderIdentifier
144
     * @param bool $recursive
145
     * @return string the Identifier of the new folder
146
     */
147
    public function createFolder($newFolderName, $parentFolderIdentifier = '', $recursive = false)
148
    {
149
        $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
150
        $newFolderName = trim($newFolderName, '/');
151
152
        $newFolderName = $this->sanitizeFileName($newFolderName);
153
        $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
154
        $this->filesystem->createDir($newIdentifier);
155 3
156
        return $newIdentifier;
157 3
    }
158
159 3
    /**
160 3
     * Returns the public URL to a file.
161
     * Either fully qualified URL or relative to PATH_site (rawurlencoded).
162
     *
163
     * @param string $identifier
164
     * @return string
165
     */
166
    public function getPublicUrl($identifier)
167
    {
168
        return '/';
169
    }
170
171
    /**
172
     * Renames a folder in this storage.
173
     *
174
     * @param string $folderIdentifier
175
     * @param string $newName
176
     * @return array A map of old to new file identifiers of all affected resources
177
     */
178
    public function renameFolder($folderIdentifier, $newName)
179
    {
180
        $renameResult = $this->filesystem->rename($folderIdentifier, $newName);
181
182
        if (true === $renameResult) {
183
            return [$folderIdentifier => $newName];
184
        } else {
185
            return [$folderIdentifier => $folderIdentifier];
186
        }
187
    }
188
189
    /**
190
     * Removes a folder in filesystem.
191
     *
192
     * @param string $folderIdentifier
193 12
     * @param bool $deleteRecursively
194
     * @return bool
195 12
     * @throws FileOperationErrorException
196 12
     */
197
    public function deleteFolder($folderIdentifier, $deleteRecursively = false)
198 9
    {
199
        $folderIdentifier = ltrim($folderIdentifier, '/');
200
        $result = $this->filesystem->deleteDir(rtrim($folderIdentifier, '/'));
201
        if (false === $result) {
202
            throw new FileOperationErrorException(
203
                'Deleting folder "' . $folderIdentifier . '" failed.',
204
                1330119451
205
            );
206
        }
207 3
        return $result;
208
    }
209 3
210
    /**
211
     * Checks if a file exists.
212
     *
213
     * @param string $fileIdentifier
214
     * @return bool
215
     */
216
    public function fileExists($fileIdentifier)
217
    {
218
        if ($this->filesystem->has($fileIdentifier) && !$this->filesystem->get($fileIdentifier)->isDir()) {
219
            return true;
220
        }
221
        return false;
222
    }
223
224
    /**
225 3
     * Checks if a folder contains files and (if supported) other folders.
226
     *
227 3
     * @param string $folderIdentifier
228 3
     * @return bool TRUE if there are no files and folders within $folder
229 3
     */
230
    public function isFolderEmpty($folderIdentifier)
231 3
    {
232
        return 0 === count($this->filesystem->listContents($folderIdentifier));
233 3
    }
234
235 3
    /**
236
     * Adds a file from the local server hard disk to a given path in TYPO3s
237
     * virtual file system. This assumes that the local file exists, so no
238
     * further check is done here! After a successful the original file must
239
     * not exist anymore.
240
     *
241
     * @param string $localFilePath (within PATH_site)
242
     * @param string $targetFolderIdentifier
243 3
     * @param string $newFileName optional, if not given original name is used
244
     * @param bool $removeOriginal if set the original file will be removed
245 3
     *                                after successful operation
246
     * @return string the identifier of the new file
247
     */
248 3
    public function addFile($localFilePath, $targetFolderIdentifier, $newFileName = '', $removeOriginal = true)
249 3
    {
250
        $localFilePath = $this->canonicalizeAndCheckFilePath($localFilePath);
251
        $newFileName = $this->sanitizeFileName($newFileName !== '' ? $newFileName : PathUtility::basename($localFilePath));
252
        $newFileIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier) . $newFileName;
253
254
        $targetPath = ltrim($newFileIdentifier, '/');
255
256
        $content = file_get_contents($localFilePath);
257
258
        if ($removeOriginal) {
259
            if (is_uploaded_file($localFilePath)) {
260 5
                $result = $this->filesystem->put($targetPath, $content);
261
            } else {
262 3
                $result = rename($localFilePath, $targetPath);
263
            }
264
            unlink($localFilePath);
265
        } else {
266
            $result = $this->filesystem->put($targetPath, $content);
267
        }
268
        if ($result === false || !$this->filesystem->has($targetPath)) {
269 3
            throw new \RuntimeException('Adding file ' . $localFilePath . ' at ' . $newFileIdentifier . ' failed.');
270 5
        }
271 3
        clearstatcache();
272 2
        return $newFileIdentifier;
273
    }
274 3
275 3
    /**
276
     * Creates a new (empty) file and returns the identifier.
277 3
     *
278
     * @param string $fileName
279
     * @param string $parentFolderIdentifier
280
     * @return string
281 3
     * @throws InvalidFileNameException
282
     */
283
    public function createFile($fileName, $parentFolderIdentifier)
284
    {
285
        if (!$this->isValidFilename($fileName)) {
286
            throw new InvalidFileNameException(
287
                'Invalid characters in fileName "' . $fileName . '"',
288
                1320572272
289
            );
290
        }
291
292
        $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
293
        $fileIdentifier = $this->canonicalizeAndCheckFileIdentifier(
294
            $parentFolderIdentifier . $this->sanitizeFileName(ltrim($fileName, '/'))
295
        );
296
297
        $path = ltrim($parentFolderIdentifier . $fileName, '/');
298
        $result = $this->filesystem->put($path, '');
299
300
        if ($result !== true) {
301
            throw new \RuntimeException('Creating file ' . $fileIdentifier . ' failed.', 1320569854);
302
        }
303
304
        return $fileIdentifier;
305
    }
306
307
    /**
308
     * Copies a file *within* the current storage.
309
     * Note that this is only about an inner storage copy action,
310
     * where a file is just copied to another folder in the same storage.
311
     *
312
     * @param string $fileIdentifier
313
     * @param string $targetFolderIdentifier
314
     * @param string $fileName
315
     * @return string the Identifier of the new file
316
     */
317
    public function copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName)
318
    {
319
        // TODO: Implement copyFileWithinStorage() method.
320
        DebuggerUtility::var_dump([
321
            '$fileIdentifier' => $fileIdentifier,
322
            '$targetFolderIdentifier' => $targetFolderIdentifier,
323
            '$fileName' => $fileName
324
        ], 'copyFileWithinStorage');
325
    }
326
327
    /**
328
     * Renames a file in this storage.
329
     *
330
     * @param string $fileIdentifier
331
     * @param string $newName The target path (including the file name!)
332
     * @return string The identifier of the file after renaming
333
     */
334
    public function renameFile($fileIdentifier, $newName)
335
    {
336
        // TODO: Implement renameFile() method.
337
        DebuggerUtility::var_dump([
338
            '$fileIdentifier' => $fileIdentifier,
339
            '$newName' => $newName
340
        ], 'renameFile');
341
    }
342
343
    /**
344 3
     * Replaces a file with file in local file system.
345
     *
346 3
     * @param string $fileIdentifier
347
     * @param string $localFilePath
348
     * @return bool TRUE if the operation succeeded
349
     */
350
    public function replaceFile($fileIdentifier, $localFilePath)
351
    {
352
        // TODO: Implement replaceFile() method.
353
        DebuggerUtility::var_dump([
354
            '$fileIdentifier' => $fileIdentifier,
355
            '$localFilePath' => $localFilePath
356
        ], 'replaceFile');
357
    }
358
359
    /**
360
     * Removes a file from the filesystem. This does not check if the file is
361
     * still used or if it is a bad idea to delete it for some other reason
362
     * this has to be taken care of in the upper layers (e.g. the Storage)!
363
     *
364
     * @param string $fileIdentifier
365
     * @return bool TRUE if deleting the file succeeded
366
     */
367
    public function deleteFile($fileIdentifier)
368
    {
369
        return $this->filesystem->delete($fileIdentifier);
370
    }
371
372
    /**
373
     * Creates a hash for a file.
374
     *
375
     * @param string $fileIdentifier
376
     * @param string $hashAlgorithm The hash algorithm to use
377
     * @return string
378
     */
379
    public function hash($fileIdentifier, $hashAlgorithm)
380
    {
381
        if (!in_array($hashAlgorithm, ['sha1', 'md5'])) {
382
            throw new \InvalidArgumentException(
383
                'Hash algorithm "' . $hashAlgorithm . '" is not supported.',
384
                1304964032
385
            );
386
        }
387
        $propertiesToHash = ['name', 'size', 'mtime', 'identifier'];
388
        switch ($hashAlgorithm) {
389
            case 'sha1':
390
                $hash = sha1(implode('-', $this->getFileInfoByIdentifier($fileIdentifier, $propertiesToHash)));
391
                break;
392
            case 'md5':
393
                $hash = md5(implode('-', $this->getFileInfoByIdentifier($fileIdentifier, $propertiesToHash)));
394
                break;
395
            default:
396
                throw new \RuntimeException('Hash algorithm ' . $hashAlgorithm . ' is not implemented.', 1329644451);
397
        }
398
        return $hash;
399
    }
400
401
    /**
402
     * Moves a file *within* the current storage.
403
     * Note that this is only about an inner-storage move action,
404
     * where a file is just moved to another folder in the same storage.
405
     *
406
     * @param string $fileIdentifier
407
     * @param string $targetFolderIdentifier
408
     * @param string $newFileName
409
     * @return string
410
     */
411 3
    public function moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName)
412
    {
413 3
        // TODO: Implement moveFileWithinStorage() method.
414
    }
415
416
    /**
417
     * Folder equivalent to moveFileWithinStorage().
418
     *
419
     * @param string $sourceFolderIdentifier
420
     * @param string $targetFolderIdentifier
421
     * @param string $newFolderName
422
     * @return array All files which are affected, map of old => new file identifiers
423 3
     */
424
    public function moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
425 3
    {
426
        // TODO: Implement moveFolderWithinStorage() method.
427 3
    }
428
429
    /**
430
     * Folder equivalent to copyFileWithinStorage().
431
     *
432
     * @param string $sourceFolderIdentifier
433
     * @param string $targetFolderIdentifier
434
     * @param string $newFolderName
435
     * @return bool
436
     */
437 3
    public function copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
438
    {
439 3
        // TODO: Implement copyFolderWithinStorage() method.
440 3
    }
441 3
442
    /**
443
     * Returns the contents of a file. Beware that this requires to load the
444
     * complete file into memory and also may require fetching the file from an
445
     * external location. So this might be an expensive operation (both in terms
446
     * of processing resources and money) for large files.
447
     *
448
     * @param string $fileIdentifier
449
     * @return string The file contents
450
     */
451 3
    public function getFileContents($fileIdentifier)
452
    {
453 3
        return $this->filesystem->read($fileIdentifier);
454 3
    }
455 3
456
    /**
457
     * Sets the contents of a file to the specified value.
458
     *
459
     * @param string $fileIdentifier
460
     * @param string $contents
461
     * @return int The number of bytes written to the file
462
     */
463
    public function setFileContents($fileIdentifier, $contents)
464
    {
465
        $this->filesystem->put($fileIdentifier, $contents);
466
467
        return $this->filesystem->getSize($fileIdentifier);
468
    }
469
470
    /**
471
     * Checks if a file inside a folder exists
472
     *
473
     * @param string $fileName
474
     * @param string $folderIdentifier
475
     * @return bool
476
     */
477
    public function fileExistsInFolder($fileName, $folderIdentifier)
478
    {
479
        $identifier = $folderIdentifier . '/' . $fileName;
480
        $identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
481
        return $this->fileExists($identifier);
482
    }
483
484
    /**
485
     * Checks if a folder inside a folder exists.
486
     *
487
     * @param string $folderName
488
     * @param string $folderIdentifier
489
     * @return bool
490
     */
491
    public function folderExistsInFolder($folderName, $folderIdentifier)
492
    {
493
        $identifier = $folderIdentifier . '/' . $folderName;
494
        $identifier = $this->canonicalizeAndCheckFolderIdentifier($identifier);
495
        return $this->folderExists($identifier);
496
    }
497
498
    /**
499
     * Returns a path to a local copy of a file for processing it. When changing the
500
     * file, you have to take care of replacing the current version yourself!
501
     *
502
     * @param string $fileIdentifier
503
     * @param bool $writable Set this to FALSE if you only need the file for read
504
     *                       operations. This might speed up things, e.g. by using
505
     *                       a cached local version. Never modify the file if you
506
     *                       have set this flag!
507
     * @return string The path to the file on the local disk
508
     */
509
    public function getFileForLocalProcessing($fileIdentifier, $writable = true)
510
    {
511
        // TODO: Implement getFileForLocalProcessing() method.
512
        DebuggerUtility::var_dump([
513
            '$fileIdentifier' => $fileIdentifier,
514
            '$writable' => $writable,
515
        ], 'getFileForLocalProcessing');
516
    }
517
518
    /**
519
     * Returns the permissions of a file/folder as an array
520
     * (keys r, w) of boolean flags
521
     *
522
     * @param string $identifier
523
     * @return array
524
     */
525
    public function getPermissions($identifier)
526
    {
527
        return array(
528
            'r' => true,
529
            'w' => true,
530
        );
531
    }
532
533
    /**
534
     * Directly output the contents of the file to the output
535
     * buffer. Should not take care of header files or flushing
536
     * buffer before. Will be taken care of by the Storage.
537
     *
538
     * @param string $identifier
539
     * @return void
540
     */
541
    public function dumpFileContents($identifier)
542
    {
543
        // TODO: Implement dumpFileContents() method.
544
        DebuggerUtility::var_dump([
545
            '$identifier' => $identifier,
546
        ], 'dumpFileContents');
547
    }
548
549
    /**
550
     * Checks if a given identifier is within a container, e.g. if
551
     * a file or folder is within another folder.
552
     * This can e.g. be used to check for web-mounts.
553
     *
554
     * Hint: this also needs to return TRUE if the given identifier
555
     * matches the container identifier to allow access to the root
556
     * folder of a filemount.
557
     *
558
     * @param string $folderIdentifier
559
     * @param string $identifier identifier to be checked against $folderIdentifier
560
     * @return bool TRUE if $content is within or matches $folderIdentifier
561
     */
562 3
    public function isWithin($folderIdentifier, $identifier)
563
    {
564 3
        $folderIdentifier = $this->canonicalizeAndCheckFileIdentifier($folderIdentifier);
565
        $entryIdentifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
566
        if ($folderIdentifier === $entryIdentifier) {
567 3
            return true;
568 3
        }
569 3
        // File identifier canonicalization will not modify a single slash so
570 2
        // we must not append another slash in that case.
571
        if ($folderIdentifier !== '/') {
572
            $folderIdentifier .= '/';
573
        }
574
        return GeneralUtility::isFirstPartOfStr($entryIdentifier, $folderIdentifier);
575
    }
576
577
    /**
578
     * Returns information about a file.
579
     *
580
     * @param string $fileIdentifier
581
     * @param array $propertiesToExtract Array of properties which are be extracted
582
     *                                   If empty all will be extracted
583
     * @return array
584
     * @throws FileDoesNotExistException
585
     */
586
    public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = [])
587
    {
588
        $relativeDriverPath = ltrim($fileIdentifier, '/');
589
        if (!$this->filesystem->has($relativeDriverPath) || !$this->filesystem->get($relativeDriverPath)->isFile()) {
590
            throw new FileDoesNotExistException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
591
        }
592
        $dirPath = PathUtility::dirname($fileIdentifier);
593
        $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath);
594
        return $this->extractFileInformation($relativeDriverPath, $dirPath, $propertiesToExtract);
595
    }
596
597
    /**
598
     * Returns information about a file.
599
     *
600
     * @param string $folderIdentifier
601 3
     * @return array
602
     * @throws FolderDoesNotExistException
603
     */
604
    public function getFolderInfoByIdentifier($folderIdentifier)
605
    {
606
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
607
608
        if (!$this->folderExists($folderIdentifier)) {
609
            throw new FolderDoesNotExistException(
610 3
                'Folder "' . $folderIdentifier . '" does not exist.',
611 3
                1314516810
612 3
            );
613
        }
614
        return [
615
            'identifier' => $folderIdentifier,
616
            'name' => PathUtility::basename($folderIdentifier),
617 3
            'storage' => $this->storageUid
618 3
        ];
619 3
    }
620 2
621 2
    /**
622
     * Returns the identifier of a file inside the folder
623 3
     *
624
     * @param string $fileName
625
     * @param string $folderIdentifier
626
     * @return string file identifier
627
     */
628
    public function getFileInFolder($fileName, $folderIdentifier)
629
    {
630
        return $this->canonicalizeAndCheckFileIdentifier($folderIdentifier . '/' . $fileName);
631
    }
632
633 3
    /**
634
     * Returns a list of files inside the specified path
635 3
     *
636 3
     * @param string $folderIdentifier
637
     * @param int $start
638
     * @param int $numberOfItems
639
     * @param bool $recursive
640
     * @param array $filenameFilterCallbacks callbacks for filtering the items
641
     * @param string $sort Property name used to sort the items.
642
     *                     Among them may be: '' (empty, no sorting), name,
643
     *                     fileext, size, tstamp and rw.
644
     *                     If a driver does not support the given property, it
645
     *                     should fall back to "name".
646
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
647
     * @return array of FileIdentifiers
648
     */
649
    public function getFilesInFolder(
650
        $folderIdentifier,
651
        $start = 0,
652
        $numberOfItems = 0,
653
        $recursive = false,
654
        array $filenameFilterCallbacks = [],
655
        $sort = '',
656
        $sortRev = false
657
    ) {
658 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
659
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
660
        $files = [];
661
662
        /*
663
         * Filter directories
664
         */
665
        foreach ($contents as $directoryItem) {
666
            if ('file' === $directoryItem['type']) {
667 3
                $files['/' . $directoryItem['path']] = '/' . $directoryItem['path'];
668 3
            }
669 3
        }
670
671
        return $files;
672
    }
673
674 3
    /**
675 3
     * Returns the identifier of a folder inside the folder
676 3
     *
677 3
     * @param string $folderName The name of the target folder
678 2
     * @param string $folderIdentifier
679 2
     * @return string folder identifier
680
     */
681 3
    public function getFolderInFolder($folderName, $folderIdentifier)
682
    {
683
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier . '/' . $folderName);
684
        return $folderIdentifier;
685
    }
686
687
    /**
688
     * Returns a list of folders inside the specified path
689
     *
690
     * @param string $folderIdentifier
691
     * @param int $start
692
     * @param int $numberOfItems
693
     * @param bool $recursive
694
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
695
     * @param string $sort Property name used to sort the items.
696
     *                     Among them may be: '' (empty, no sorting), name,
697
     *                     fileext, size, tstamp and rw.
698
     *                     If a driver does not support the given property, it
699
     *                     should fall back to "name".
700
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
701
     * @return array of Folder Identifier
702
     * @TODO: Implement pagination with $start and $numberOfItems
703
     * @TODO: Implement directory filter callbacks
704
     * @TODO: Implement sorting
705
     */
706
    public function getFoldersInFolder(
707
        $folderIdentifier,
708 3
        $start = 0,
709
        $numberOfItems = 0,
710 3
        $recursive = false,
711 3
        array $folderNameFilterCallbacks = [],
712 3
        $sort = '',
713 3
        $sortRev = false
714 3
    ) {
715 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
716 2
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
717 2
        $directories = [];
718
719 3
        /*
720
         * Filter directories
721
         */
722
        foreach ($contents as $directoryItem) {
723
            if ('dir' === $directoryItem['type']) {
724
                $directories['/' . $directoryItem['path']]
725
                    = '/' . $directoryItem['path'];
726
            }
727
        }
728
729
        return $directories;
730
    }
731
732
    /**
733
     * Returns the number of files inside the specified path
734
     *
735
     * @param string $folderIdentifier
736
     * @param bool $recursive
737
     * @param array $filenameFilterCallbacks callbacks for filtering the items
738
     * @return int Number of files in folder
739
     * @TODO: Implement recursive count
740
     * @TODO: Implement filename filtering
741
     */
742
    public function countFilesInFolder($folderIdentifier, $recursive = false, array $filenameFilterCallbacks = [])
743
    {
744
745
        return count($this->getFilesInFolder($folderIdentifier, 0, 0, $recursive, $filenameFilterCallbacks));
746
    }
747
748
    /**
749
     * Returns the number of folders inside the specified path
750
     *
751
     * @param string $folderIdentifier
752
     * @param bool $recursive
753
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
754
     * @return int Number of folders in folder
755
     */
756
    public function countFoldersInFolder($folderIdentifier, $recursive = false, array $folderNameFilterCallbacks = [])
757
    {
758
        $count = 0;
759
        $filesystemRelativeIdentifier = ltrim($folderIdentifier, '/');
760
        $directoryListing = $this->filesystem->listContents($filesystemRelativeIdentifier);
761
        foreach ($directoryListing as $entry) {
762
            if ('dir' === $entry['type']) {
763
                $count++;
764
            }
765
        }
766
767
        return $count;
768
    }
769
770
    /**
771
     * Extracts information about a file from the filesystem.
772
     *
773
     * @param string $filePath The absolute path to the file
774
     * @param string $containerPath The relative path to the file's container
775
     * @param array $propertiesToExtract array of properties which should be returned, if empty all will be extracted
776
     * @return array
777
     */
778
    protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = array())
779
    {
780
        if (empty($propertiesToExtract)) {
781
            $propertiesToExtract = array(
782
                'size',
783
                'atime',
784
                'atime',
785
                'mtime',
786
                'ctime',
787
                'mimetype',
788
                'name',
789
                'identifier',
790
                'identifier_hash',
791
                'storage',
792
                'folder_hash'
793
            );
794
        }
795
        $fileInformation = array();
796
        foreach ($propertiesToExtract as $property) {
797
            $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
798
        }
799
        return $fileInformation;
800
    }
801
802
    /**
803
     * Extracts a specific FileInformation from the FileSystems.
804
     *
805
     * @param string $fileIdentifier
806
     * @param string $containerPath
807
     * @param string $property
808
     *
809
     * @return bool|int|string
810
     * @throws \InvalidArgumentException
811
     */
812
    public function getSpecificFileInformation($fileIdentifier, $containerPath, $property)
813
    {
814
        $identifier = $this->canonicalizeAndCheckFileIdentifier($containerPath . PathUtility::basename($fileIdentifier));
815
        $file = $this->filesystem->getMetadata($fileIdentifier);
816
817
        switch ($property) {
818
            case 'size':
819
                return $file['size'];
820
            case 'atime':
821
                return $file['timestamp'];
822
            case 'mtime':
823
                return $file['timestamp'];
824
            case 'ctime':
825
                return $file['timestamp'];
826
            case 'name':
827
                return PathUtility::basename($fileIdentifier);
828
            case 'mimetype':
829
                return 'application/octet-stream';
830
            case 'identifier':
831
                return $identifier;
832
            case 'storage':
833
                return $this->storageUid;
834
            case 'identifier_hash':
835
                return $this->hashIdentifier($identifier);
836
            case 'folder_hash':
837
                return $this->hashIdentifier($this->getParentFolderIdentifierOfIdentifier($identifier));
838
            default:
839
                throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
840
        }
841
    }
842
}
843