From 338cf9d0acd532a7ffb16e3258df1b85c2ee4650 Mon Sep 17 00:00:00 2001
From: Tomas Norre Mikkelsen <tomas.mikkelsen@aoe.com>
Date: Thu, 13 Jul 2017 18:08:37 +0200
Subject: [PATCH] [BUGFIX] Extend Lowlevel lost_files to accept customPath

This allows the lowlevel lost_files cleaner to use
customPaths as input too.

Resolves: #72202
Releases: master,8.7
Change-Id: I1481d036c8c337eee54a97d8a192d6a39a6af404
Reviewed-on: https://review.typo3.org/45238
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Stefan Rotsch <stefan.rotsch@aoe.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Joerg Boesche <typo3@joergboesche.de>
Reviewed-by: Henning Liebe <h.liebe@neusta.de>
Tested-by: Henning Liebe <h.liebe@neusta.de>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 .../Classes/Command/LostFilesCommand.php      | 40 +++++++++++++++----
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/typo3/sysext/lowlevel/Classes/Command/LostFilesCommand.php b/typo3/sysext/lowlevel/Classes/Command/LostFilesCommand.php
index 33b7cdb26c01..40f24a84dc8f 100644
--- a/typo3/sysext/lowlevel/Classes/Command/LostFilesCommand.php
+++ b/typo3/sysext/lowlevel/Classes/Command/LostFilesCommand.php
@@ -45,11 +45,11 @@ Assumptions:
 - index.html, .htaccess files and RTEmagic* image files (ignored)
 - Files found in deleted records are included (otherwise you would see a false list of lost files)
 
-The assumptions are not requirements by the TYPO3 API but reflects the de facto implementation of most TYPO3 installations and therefore a practical approach to cleaning up the uploads/ folder.
+The assumptions are not requirements by the TYPO3 API but reflects the de facto implementation of most TYPO3 installations and therefore a practical approach to cleaning up the uploads/ or costum folder.
 Therefore, if all "group" type fields in TCA and flexforms are positioned inside the uploads/ folder and if no files inside are managed manually it should be safe to clean out files with no relations found in the system.
-Under such circumstances there should theoretically be no lost files in the uploads/ folder since DataHandler should have managed relations automatically including adding and deleting files.
+Under such circumstances there should theoretically be no lost files in the uploads/ or custom folder since DataHandler should have managed relations automatically including adding and deleting files.
 However, there is at least one reason known to why files might be found lost and that is when FlexForms are used. In such a case a change of/in the Data Structure XML (or the ability of the system to find the Data Structure definition!) used for the flexform could leave lost files behind. This is not unlikely to happen when records are deleted. More details can be found in a note to the function FlexFormTools->getDataStructureIdentifier()
-Another scenario could of course be de-installation of extensions which managed files in the uploads/ folders.
+Another scenario could of course be de-installation of extensions which managed files in the uploads/ or custom folders.
 
 If the option "--dry-run" is not set, the files are then deleted automatically.
 Warning: First, make sure those files are not used somewhere TYPO3 does not know about! See the assumptions above.
@@ -72,6 +72,12 @@ If you want to get more detailed information, use the --verbose option.')
                 null,
                 InputOption::VALUE_NONE,
                 'Setting this option automatically updates the reference index and does not ask on command line. Alternatively, use -n to avoid the interactive mode'
+            )
+            ->addOption(
+                'custom-path',
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Comma separated list of paths to process. Example: "fileadmin/[path1],fileadmin/[path2],...", if not passed, uploads/ will be used by default.'
             );
     }
 
@@ -102,7 +108,14 @@ If you want to get more detailed information, use the --verbose option.')
         } else {
             $excludedPaths = [];
         }
-        $lostFiles = $this->findLostFiles($excludedPaths);
+
+        // Use custom-path
+        $customPaths = '';
+        if ($input->hasOption('custom-path') && !empty($input->getOption('custom-path'))) {
+            $customPaths = $input->getOption('custom-path');
+        }
+
+        $lostFiles = $this->findLostFiles($excludedPaths, $customPaths);
 
         if (count($lostFiles)) {
             if (!$io->isQuiet()) {
@@ -151,18 +164,31 @@ If you want to get more detailed information, use the --verbose option.')
     }
 
     /**
-     * Find lost files in uploads/ folder
+     * Find lost files in uploads/ or custom folder
      *
      * @param array $excludedPaths list of paths to be excluded, can be uploads/pics/
+     * @param string $customPaths list of paths to be checked instead of uploads/
      * @return array an array of files (relative to PATH_site) that are not connected
      */
-    protected function findLostFiles($excludedPaths = []): array
+    protected function findLostFiles($excludedPaths = [], $customPaths = ''): array
     {
         $lostFiles = [];
 
         // Get all files
         $files = [];
-        $files = GeneralUtility::getAllFilesAndFoldersInPath($files, PATH_site . 'uploads/');
+        if (!empty($customPaths)) {
+            $customPaths = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $customPaths, true);
+            foreach ($customPaths as $customPath) {
+                if (false === realpath(PATH_site . $customPath)
+                    || !GeneralUtility::isFirstPartOfStr(realpath(PATH_site . $customPath), realpath(PATH_site))) {
+                    throw new \Exception('The path: "' . $customPath . '" is invalid', 1450086736);
+                }
+                $files = GeneralUtility::getAllFilesAndFoldersInPath($files, PATH_site . $customPath);
+            }
+        } else {
+            $files = GeneralUtility::getAllFilesAndFoldersInPath($files, PATH_site . 'uploads/');
+        }
+
         $files = GeneralUtility::removePrefixPathFromList($files, PATH_site);
 
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-- 
GitLab