Completed
Push — master ( 4af5ab...d26efc )
by
unknown
16:50
created

Typo3tempFileService::clearAssetsFolder()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 6
nop 1
dl 0
loc 32
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Install\Service;
17
18
use Symfony\Component\Finder\Finder;
19
use Symfony\Component\Finder\SplFileInfo;
20
use TYPO3\CMS\Core\Core\Environment;
21
use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
22
use TYPO3\CMS\Core\Resource\ResourceStorage;
23
use TYPO3\CMS\Core\Resource\StorageRepository;
24
use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26
/**
27
 * Service class to manage typo3temp/assets and FAL storage
28
 * processed file statistics / cleanup.
29
 * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
30
 */
31
class Typo3tempFileService
32
{
33
    private $processedFileRepository;
34
    private $storageRepository;
35
36
    public function __construct(ProcessedFileRepository $processedFileRepository, StorageRepository $storageRepository)
37
    {
38
        $this->processedFileRepository = $processedFileRepository;
39
        $this->storageRepository = $storageRepository;
40
    }
41
42
    /**
43
     * Returns a list of directory names in typo3temp/assets and their number of files
44
     *
45
     * @return array
46
     */
47
    public function getDirectoryStatistics(): array
48
    {
49
        return array_merge(
50
            $this->statsFromTypo3temp(),
51
            $this->statsFromStorages()
52
        );
53
    }
54
55
    public function getStatsFromStorageByUid(int $storageUid): array
56
    {
57
        $storage = $this->storageRepository->findByUid($storageUid);
58
        return $this->getStatsFromStorage($storage);
0 ignored issues
show
Bug introduced by
It seems like $storage can also be of type null; however, parameter $storage of TYPO3\CMS\Install\Servic...::getStatsFromStorage() does only seem to accept TYPO3\CMS\Core\Resource\ResourceStorage, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
        return $this->getStatsFromStorage(/** @scrutinizer ignore-type */ $storage);
Loading history...
59
    }
60
61
    /**
62
     * Directory statistics for typo3temp/assets folders with some
63
     * special handling for legacy processed file storage _processed_
64
     *
65
     * @return array
66
     */
67
    protected function statsFromTypo3temp(): array
68
    {
69
        $stats = [];
70
        $typo3TempAssetsPath = '/typo3temp/assets/';
71
        $basePath = Environment::getPublicPath() . $typo3TempAssetsPath;
72
        if (is_dir($basePath)) {
73
            $dirFinder = new Finder();
74
            $dirsInAssets = $dirFinder->directories()->in($basePath)->depth(0)->sortByName();
75
            foreach ($dirsInAssets as $dirInAssets) {
76
                /** @var SplFileInfo $dirInAssets */
77
                $fileFinder = new Finder();
78
                $fileCount = $fileFinder->files()->in($dirInAssets->getPathname())->count();
79
                $folderName = $dirInAssets->getFilename();
80
                $stat = [
81
                    'directory' => $typo3TempAssetsPath . $folderName,
82
                    'numberOfFiles' => $fileCount,
83
                ];
84
                if ($folderName === '_processed_') {
85
                    // The processed file storage for legacy files (eg. TCA type=group internal_type=file)
86
                    // gets the storageUid set, so this one can be removed via FAL functionality
87
                    $stat['storageUid'] = 0;
88
                }
89
                $stats[] = $stat;
90
            }
91
        }
92
        return $stats;
93
    }
94
95
    /**
96
     * Directory statistics for configured FAL storages.
97
     *
98
     * @return array
99
     */
100
    protected function statsFromStorages(): array
101
    {
102
        $stats = [];
103
        $storages = $this->storageRepository->findAll();
104
        foreach ($storages as $storage) {
105
            if ($storage->isOnline()) {
106
                $stats[] = $this->getStatsFromStorage($storage);
107
            }
108
        }
109
        return $stats;
110
    }
111
112
    protected function getStatsFromStorage(ResourceStorage $storage): array
113
    {
114
        $storageConfiguration = $storage->getConfiguration();
115
        $storageBasePath = rtrim($storageConfiguration['basePath'], '/');
116
        $processedPath = '/' . $storageBasePath . $storage->getProcessingFolder()->getIdentifier();
117
        $numberOfFiles = $this->processedFileRepository->countByStorage($storage);
118
119
        return [
120
            'directory' => $processedPath,
121
            'numberOfFiles' => $numberOfFiles,
122
            'storageUid' => $storage->getUid()
123
        ];
124
    }
125
126
    /**
127
     * Clear processed files. The sys_file_processedfile table is cleared for
128
     * given storage uid and the physical files of local processed storages are deleted.
129
     *
130
     * @return int 0 if all went well, if >0 this number of files that could not be deleted
131
     */
132
    public function clearProcessedFiles(int $storageUid): int
133
    {
134
        $repository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
135
        return $repository->removeAll($storageUid);
136
    }
137
138
    /**
139
     * Clears files and folders in a typo3temp/assets/ folder (not _processed_!)
140
     *
141
     * @param string $folderName
142
     * @return bool TRUE if all went well
143
     * @throws \RuntimeException If folder path is not valid
144
     */
145
    public function clearAssetsFolder(string $folderName)
146
    {
147
        $basePath = Environment::getPublicPath() . $folderName;
148
        if (empty($folderName)
149
            || !GeneralUtility::isAllowedAbsPath($basePath)
150
            || strpos($folderName, '/typo3temp/assets/') !== 0
151
        ) {
152
            throw new \RuntimeException(
153
                'Path to folder ' . $folderName . ' not allowed.',
154
                1501781453
155
            );
156
        }
157
        if (!is_dir($basePath)) {
158
            throw new \RuntimeException(
159
                'Folder path ' . $basePath . ' does not exist or is no directory.',
160
                1501781454
161
            );
162
        }
163
164
        // first remove directories
165
        foreach ((new Finder())->directories()->in($basePath)->depth(0) as $directory) {
166
            /** @var SplFileInfo $directory */
167
            GeneralUtility::rmdir($directory->getPathname(), true);
168
        }
169
170
        // then remove files directly in the main dir
171
        foreach ((new Finder())->files()->in($basePath)->depth(0) as $file) {
172
            /** @var SplFileInfo $file */
173
            $path = $file->getPathname();
174
            @unlink($path);
175
        }
176
        return true;
177
    }
178
}
179