‪TYPO3CMS  ‪main
CleanUpLocalProcessedFilesService.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
23 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
30 
35 {
36  protected const ‪TABLE_NAME = 'sys_file_processedfile';
37  protected const ‪DRIVER = 'Local';
38 
42  public function ‪getFilesToClean(int $limit = 0): array
43  {
44  $queryBuilder = $this->‪getQueryBuilderWithoutRestrictions();
45  $localStorages = GeneralUtility::makeInstance(StorageRepository::class)->findByStorageType(self::DRIVER);
46 
47  $queryBuilder
48  ->count('*')
49  ->from(self::TABLE_NAME)
50  ->where(
51  // processed file identifier (placeholder pos 1)
52  $queryBuilder->expr()->eq(
53  'identifier',
54  $queryBuilder->createPositionalParameter('')
55  ),
56  // we need to ensure to search an identifier only for the responsible storage ( placeholder pos 2)
57  $queryBuilder->expr()->eq(
58  'storage',
59  $queryBuilder->createPositionalParameter(0, ‪Connection::PARAM_INT)
60  )
61  );
62  $statement = $queryBuilder->prepare();
63 
64  $files = [];
65  foreach ($localStorages as $storage) {
66  $storageBasePath = ‪PathUtility::stripPathSitePrefix($this->‪getAbsoluteBasePath($storage->getConfiguration()));
67  foreach ($storage->getProcessingFolders() as $folder) {
68  foreach ($this->‪getFilesOfFolderRecursive($folder) as $splFileInfo) {
69  if ($splFileInfo->getRealPath() === false) {
70  continue;
71  }
72 
73  // prepare identifier for proper lookup
74  $filePath = '/' . mb_substr(
75  ‪PathUtility::stripPathSitePrefix($splFileInfo->getRealPath()),
76  mb_strlen(trim($storageBasePath, '/') . '/')
77  );
78 
79  // reuse prepared statement to find processed files without any processed record entries in matching
80  // storage, using `$filePath` as equal match for field `identifier` and storage uid.
81  $statement->bindValue(1, $filePath);
82  $statement->bindValue(2, $storage->getUid(), ‪Connection::PARAM_INT);
83  if ((int)$statement->executeQuery()->fetchOne() === 0) {
84  $files[] = $splFileInfo;
85  }
86  }
87  }
88  }
89 
90  return $files;
91  }
92 
96  public function ‪getRecordsToClean(): array
97  {
98  $storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
99  $queryBuilder = $this->‪getQueryBuilderWithoutRestrictions();
100  $queryBuilder
101  ->select('sfp.storage', 'sfp.identifier', 'sfp.uid')
102  ->from(self::TABLE_NAME, 'sfp')
103  ->leftJoin(
104  'sfp',
105  'sys_file_storage',
106  'sfs',
107  $queryBuilder->expr()->eq(
108  'sfp.storage',
109  $queryBuilder->quoteIdentifier('sfs.uid')
110  )
111  )
112  ->where(
113  $queryBuilder->expr()->neq(
114  'sfp.identifier',
115  $queryBuilder->createNamedParameter('')
116  ),
117  $queryBuilder->expr()->eq(
118  'sfs.driver',
119  $queryBuilder->createNamedParameter(self::DRIVER)
120  )
121  );
122 
123  $results = $queryBuilder->executeQuery();
124  $processedToDelete = [];
125  while ($processedFile = $results->fetchAssociative()) {
126  $storage = $storageRepository->findByUid((int)$processedFile['storage']);
127  $processedPathAndFileIdentifier = (string)$processedFile['identifier'];
128 
129  // Storage does no longer have that file => delete entry
130  if ($storage !== null && !$storage->hasFile($processedPathAndFileIdentifier)) {
131  $processedToDelete[] = $processedFile;
132  }
133  }
134 
135  return $processedToDelete;
136  }
137 
144  protected function ‪getFilesOfFolderRecursive(‪Folder $folder): iterable
145  {
146  try {
147  $basePath = $this->‪getAbsoluteBasePath($folder->‪getStorage()->getConfiguration());
148  } catch (‪InvalidPathException | ‪InvalidConfigurationException $invalidPathException) {
149  return [];
150  }
151 
152  $iterator = new \RecursiveIteratorIterator(
153  new \RecursiveDirectoryIterator(
154  $basePath . $folder->‪getIdentifier(),
155  \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::CURRENT_AS_FILEINFO
156  ),
157  \RecursiveIteratorIterator::SELF_FIRST,
158  \RecursiveIteratorIterator::CATCH_GET_CHILD
159  );
160  foreach ($iterator as $splFileInfo) {
161  if ($splFileInfo instanceof \SplFileInfo && $splFileInfo->isFile()) {
162  yield $splFileInfo;
163  }
164  }
165  }
166 
167  protected function ‪getAbsoluteBasePath(array $configuration): string
168  {
169  if (!array_key_exists('basePath', $configuration) || empty($configuration['basePath'])) {
171  'Configuration must contain base path.',
172  1640297535
173  );
174  }
175 
176  $absoluteBasePath = $configuration['basePath'];
177  if (!empty($configuration['pathType']) && $configuration['pathType'] === 'relative') {
178  $relativeBasePath = $configuration['basePath'];
179  $absoluteBasePath = ‪Environment::getPublicPath() . '/' . $relativeBasePath;
180  }
181  $absoluteBasePath = ‪PathUtility::getCanonicalPath($absoluteBasePath);
182  $absoluteBasePath = rtrim($absoluteBasePath, '/') . '/';
183  if (!is_dir($absoluteBasePath)) {
185  'Base path "' . $absoluteBasePath . '" does not exist or is no directory.',
186  1640297526
187  );
188  }
189 
190  return $absoluteBasePath;
191  }
192 
193  public function ‪deleteRecord(array $recordUids): int
194  {
195  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE_NAME);
196  $queryBuilder->getRestrictions()->removeAll();
197 
198  return $queryBuilder->delete(self::TABLE_NAME)
199  ->where(
200  $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($recordUids, Connection::PARAM_INT_ARRAY))
201  )
202  ->executeStatement();
203  }
204 
205  protected function ‪getQueryBuilderWithoutRestrictions(): QueryBuilder
206  {
207  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE_NAME);
208  $queryBuilder->getRestrictions()->removeAll();
209 
210  return $queryBuilder;
211  }
212 }
‪TYPO3\CMS\Core\Utility\PathUtility\getCanonicalPath
‪static string getCanonicalPath(string $path)
Definition: PathUtility.php:364
‪TYPO3\CMS\Core\Utility\PathUtility\stripPathSitePrefix
‪static stripPathSitePrefix(string $path)
Definition: PathUtility.php:428
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\getAbsoluteBasePath
‪getAbsoluteBasePath(array $configuration)
Definition: CleanUpLocalProcessedFilesService.php:167
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:46
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\getRecordsToClean
‪getRecordsToClean()
Definition: CleanUpLocalProcessedFilesService.php:96
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\getQueryBuilderWithoutRestrictions
‪getQueryBuilderWithoutRestrictions()
Definition: CleanUpLocalProcessedFilesService.php:205
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static getPublicPath()
Definition: Environment.php:187
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\getFilesOfFolderRecursive
‪SplFileInfo[] getFilesOfFolderRecursive(Folder $folder)
Definition: CleanUpLocalProcessedFilesService.php:144
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\deleteRecord
‪deleteRecord(array $recordUids)
Definition: CleanUpLocalProcessedFilesService.php:193
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\TABLE_NAME
‪const TABLE_NAME
Definition: CleanUpLocalProcessedFilesService.php:36
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\getFilesToClean
‪getFilesToClean(int $limit=0)
Definition: CleanUpLocalProcessedFilesService.php:42
‪TYPO3\CMS\Core\Resource\Exception\InvalidConfigurationException
Definition: InvalidConfigurationException.php:24
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:37
‪TYPO3\CMS\Core\Resource\StorageRepository
Definition: StorageRepository.php:38
‪TYPO3\CMS\Core\Resource\Folder\getStorage
‪getStorage()
Definition: Folder.php:138
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:35
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService
Definition: CleanUpLocalProcessedFilesService.php:35
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Lowlevel\Service
Definition: CleanUpLocalProcessedFilesService.php:18
‪TYPO3\CMS\Core\Resource\Folder\getIdentifier
‪non empty string getIdentifier()
Definition: Folder.php:149
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:51
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Lowlevel\Service\CleanUpLocalProcessedFilesService\DRIVER
‪const DRIVER
Definition: CleanUpLocalProcessedFilesService.php:37
‪TYPO3\CMS\Core\Resource\Exception\InvalidPathException
Definition: InvalidPathException.php:24