[BUGFIX] Improve install tool temporary assets removal
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Service / Typo3tempFileService.php
1 <?php
2 namespace TYPO3\CMS\Install\Service;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Symfony\Component\Finder\Finder;
18 use Symfony\Component\Finder\SplFileInfo;
19 use TYPO3\CMS\Core\Core\Environment;
20 use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
21 use TYPO3\CMS\Core\Resource\StorageRepository;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23
24 /**
25 * Service class to manage typo3temp/assets and FAL storage
26 * processed file statistics / cleanup.
27 */
28 class Typo3tempFileService
29 {
30 /**
31 * Returns a list of directory names in typo3temp/assets and their number of files
32 *
33 * @return array
34 */
35 public function getDirectoryStatistics(): array
36 {
37 return array_merge(
38 $this->statsFromTypo3temp(),
39 $this->statsFromStorages()
40 );
41 }
42
43 /**
44 * Directory statistics for typo3temp/assets folders with some
45 * special handling for legacy processed file storage _processed_
46 *
47 * @return array
48 */
49 protected function statsFromTypo3temp(): array
50 {
51 $stats = [];
52 $typo3TempAssetsPath = '/typo3temp/assets/';
53 $basePath = Environment::getPublicPath() . $typo3TempAssetsPath;
54 if (is_dir($basePath)) {
55 $dirFinder = new Finder();
56 $dirsInAssets = $dirFinder->directories()->in($basePath)->depth(0)->sortByName();
57 foreach ($dirsInAssets as $dirInAssets) {
58 /** @var SplFileInfo $dirInAssets */
59 $fileFinder = new Finder();
60 $fileCount = $fileFinder->files()->in($dirInAssets->getPathname())->count();
61 $folderName = $dirInAssets->getFilename();
62 $stat = [
63 'directory' => $typo3TempAssetsPath . $folderName,
64 'numberOfFiles' => $fileCount,
65 ];
66 if ($folderName === '_processed_') {
67 // The processed file storage for legacy files (eg. TCA type=group internal_type=file)
68 // gets the storageUid set, so this one can be removed via FAL functionality
69 $stat['storageUid'] = 0;
70 }
71 $stats[] = $stat;
72 }
73 }
74 return $stats;
75 }
76
77 /**
78 * Directory statistics for configured FAL storages.
79 *
80 * @return array
81 */
82 protected function statsFromStorages(): array
83 {
84 $stats = [];
85 $processedFileRepository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
86 $storages = GeneralUtility::makeInstance(StorageRepository::class)->findAll();
87 foreach ($storages as $storage) {
88 if ($storage->isOnline()) {
89 $storageConfiguration = $storage->getConfiguration();
90 $storageBasePath = rtrim($storageConfiguration['basePath'], '/');
91 $processedPath = '/' . $storageBasePath . $storage->getProcessingFolder()->getIdentifier();
92 $numberOfFiles = $processedFileRepository->countByStorage($storage);
93 $stats[] = [
94 'directory' => $processedPath,
95 'numberOfFiles' => $numberOfFiles,
96 'storageUid' => $storage->getUid()
97 ];
98 }
99 }
100 return $stats;
101 }
102
103 /**
104 * Clear processed files. The sys_file_processedfile table is cleared for
105 * given storage uid and the physical files of local processed storages are deleted.
106 *
107 * @return int 0 if all went well, if >0 this number of files that could not be deleted
108 */
109 public function clearProcessedFiles(int $storageUid): int
110 {
111 $repository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
112 return $repository->removeAll($storageUid);
113 }
114
115 /**
116 * Clear files in a typo3temp/assets/ folder (not _processed_!)
117 *
118 * @param string $folderName
119 * @return bool TRUE if all went well
120 * @throws \RuntimeException If folder path is not valid
121 */
122 public function clearAssetsFolder(string $folderName)
123 {
124 $basePath = Environment::getPublicPath() . $folderName;
125 if (empty($folderName)
126 || !GeneralUtility::isAllowedAbsPath($basePath)
127 || strpos($folderName, '/typo3temp/assets/') !== 0
128 ) {
129 throw new \RuntimeException(
130 'Path to folder ' . $folderName . ' not allowed.',
131 1501781453
132 );
133 }
134 if (!is_dir($basePath)) {
135 throw new \RuntimeException(
136 'Folder path ' . $basePath . ' does not exist or is no directory.',
137 1501781454
138 );
139 }
140
141 $finder = new Finder();
142 $files = $finder->files()->in($basePath)->depth(0)->sortByName();
143 foreach ($files as $file) {
144 /** @var SplFileInfo $file */
145 $path = $file->getPathname();
146 @unlink($path);
147 }
148 return true;
149 }
150 }