Passed
Push — master ( 61030c...c506e6 )
by
unknown
17:19
created

SvgFilesSanitization::executeUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
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
18
namespace TYPO3\CMS\Install\Updates;
19
20
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
21
use TYPO3\CMS\Core\Resource\File;
22
use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
23
use TYPO3\CMS\Core\Resource\ResourceStorage;
24
use TYPO3\CMS\Core\Resource\Security\SvgSanitizer;
25
use TYPO3\CMS\Core\Resource\StorageRepository;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
28
class SvgFilesSanitization implements UpgradeWizardInterface, ConfirmableInterface
29
{
30
    /**
31
     * @var StorageRepository
32
     */
33
    protected $storageRepository;
34
35
    /**
36
     * @var Confirmation
37
     */
38
    protected $confirmation;
39
40
    public function __construct()
41
    {
42
        $this->storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
43
        $this->confirmation = new Confirmation(
44
            'Continue sanitizing SVG files?',
45
            $this->getDescription(),
46
            false,
47
            'sanitize, backup available',
48
            'cancel',
49
            false
50
        );
51
    }
52
53
    /**
54
     * Return the identifier for this wizard
55
     * This should be the same string as used in the ext_localconf class registration
56
     *
57
     * @return string
58
     */
59
    public function getIdentifier(): string
60
    {
61
        // needs to be static for exact reference
62
        return 'TYPO3\CMS\Install\Updates\SvgFilesSanitization';
63
    }
64
65
    /**
66
     * Return the speaking name of this wizard
67
     *
68
     * @return string
69
     */
70
    public function getTitle(): string
71
    {
72
        return 'Sanitize existing SVG files in fileadmin folder';
73
    }
74
75
    /**
76
     * Return the description for this wizard
77
     *
78
     * @return string
79
     */
80
    public function getDescription(): string
81
    {
82
        return 'This upgrade wizard will sanitize all SVG files located in local file storages. '
83
            . 'It is very likely that file contents will be changed.' . "\n"
84
            . 'Before continuing, please ensure a proper backup of *.svg and *.svgz files is in place before continuing.';
85
    }
86
87
    /**
88
     * Is an update necessary?
89
     *
90
     * Is used to determine whether a wizard needs to be run.
91
     * Check if data for migration exists.
92
     *
93
     * @return bool
94
     */
95
    public function updateNecessary(): bool
96
    {
97
        foreach ($this->resolveLocalStorages() as $storage) {
98
            try {
99
                $svgFiles = $this->resolveSvgFiles($storage);
100
            } catch (InsufficientFolderAccessPermissionsException $exception) {
101
                continue;
102
            }
103
            if (count($svgFiles) > 0) {
104
                return true;
105
            }
106
        }
107
        return false;
108
    }
109
110
    /**
111
     * Execute the update
112
     *
113
     * Called when a wizard reports that an update is necessary
114
     *
115
     * @return bool
116
     */
117
    public function executeUpdate(): bool
118
    {
119
        return $this->processSvgFiles();
120
    }
121
122
    /**
123
     * Returns an array of class names of Prerequisite classes
124
     *
125
     * This way a wizard can define dependencies like "database up-to-date" or
126
     * "reference index updated"
127
     *
128
     * @return string[]
129
     */
130
    public function getPrerequisites(): array
131
    {
132
        return [];
133
    }
134
135
    /**
136
     * Return a confirmation message instance
137
     *
138
     * @return Confirmation
139
     */
140
    public function getConfirmation(): Confirmation
141
    {
142
        return $this->confirmation;
143
    }
144
145
    /**
146
     * @return ResourceStorage[]
147
     */
148
    protected function resolveLocalStorages(): array
149
    {
150
        return array_filter(
151
            $this->storageRepository->findByStorageType('Local'),
152
            function (ResourceStorage $storage) {
153
                return $storage->isWritable();
154
            }
155
        );
156
    }
157
158
    /**
159
     * @param ResourceStorage $storage
160
     * @return File[]
161
     * @throws InsufficientFolderAccessPermissionsException
162
     */
163
    protected function resolveSvgFiles(ResourceStorage $storage): array
164
    {
165
        $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
166
        $filter->setAllowedFileExtensions(['svg', 'svgz']);
167
        return $storage
168
            ->setFileAndFolderNameFilters([[$filter, 'filterFileList']])
169
            ->getFilesInFolder(
170
                $storage->getRootLevelFolder(),
171
                0,
172
                0,
173
                true,
174
                true
175
            );
176
    }
177
178
    protected function processSvgFiles(): bool
179
    {
180
        $successful = true;
181
        $sanitizer = GeneralUtility::makeInstance(SvgSanitizer::class);
182
        foreach ($this->resolveLocalStorages() as $storage) {
183
            try {
184
                $svgFiles = $this->resolveSvgFiles($storage);
185
            } catch (InsufficientFolderAccessPermissionsException $exception) {
186
                // @todo Add notice/warning for this upgrade process
187
                $successful = false;
188
                continue;
189
            }
190
            foreach ($svgFiles as $svgFile) {
191
                $oldFileContent = $svgFile->getContents();
192
                $newFileContent = $sanitizer->sanitizeContent($oldFileContent);
193
                if ($oldFileContent !== $newFileContent) {
194
                    $svgFile->setContents($newFileContent);
195
                }
196
            }
197
        }
198
        return $successful;
199
    }
200
}
201