[TASK] Use strict comparison for strings
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Tool / CleanUp.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Tool;
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 TYPO3\CMS\Core\Database\ConnectionPool;
18 use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21 use TYPO3\CMS\Install\Controller\Action;
22 use TYPO3\CMS\Install\Status\ErrorStatus;
23 use TYPO3\CMS\Install\Status\InfoStatus;
24 use TYPO3\CMS\Install\Status\OkStatus;
25
26 /**
27 * Clean up page
28 */
29 class CleanUp extends Action\AbstractAction
30 {
31 /**
32 * Status messages of submitted actions
33 *
34 * @var array
35 */
36 protected $actionMessages = [];
37
38 /**
39 * Executes the tool
40 *
41 * @return string Rendered content
42 */
43 protected function executeAction()
44 {
45 if (isset($this->postValues['set']['clearTables'])) {
46 $this->actionMessages[] = $this->clearSelectedTables();
47 $this->view->assign('postAction', 'clearTables');
48 }
49 if (isset($this->postValues['set']['resetBackendUserUc'])) {
50 $this->actionMessages[] = $this->resetBackendUserUc();
51 $this->view->assign('postAction', 'resetBackendUserUc');
52 }
53 if (isset($this->postValues['set']['clearProcessedFiles'])) {
54 $this->actionMessages[] = $this->clearProcessedFiles();
55 $this->view->assign('postAction', 'clearProcessedFiles');
56 }
57 if (isset($this->postValues['set']['deleteTypo3TempFiles'])) {
58 $this->view->assign('postAction', 'deleteTypo3TempFiles');
59 }
60
61 $this->view->assign('cleanableTables', $this->getCleanableTableList());
62
63 $typo3TempData = $this->getTypo3TempStatistics();
64 $this->view->assign('typo3TempData', $typo3TempData);
65
66 $this->view->assign('actionMessages', $this->actionMessages);
67 return $this->view->render();
68 }
69
70 /**
71 * Get list of existing tables that could be truncated.
72 *
73 * @return array List of cleanable tables with name, description and number of rows
74 */
75 protected function getCleanableTableList()
76 {
77 $tableCandidates = [
78 [
79 'name' => 'be_sessions',
80 'description' => 'Backend user sessions'
81 ],
82 [
83 'name' => 'cache_md5params',
84 'description' => 'Frontend redirects',
85 ],
86 [
87 'name' => 'fe_sessions',
88 'description' => 'Frontend user sessions',
89 ],
90 [
91 'name' => 'fe_session_data',
92 'description' => 'Frontend user session data',
93 ],
94 [
95 'name' => 'sys_history',
96 'description' => 'Tracking of database record changes through TYPO3 backend forms',
97 ],
98 [
99 'name' => 'sys_lockedrecords',
100 'description' => 'Record locking of backend user editing',
101 ],
102 [
103 'name' => 'sys_log',
104 'description' => 'General log table',
105 ],
106 [
107 'name' => 'sys_preview',
108 'description' => 'Workspace preview links',
109 ],
110 [
111 'name' => 'tx_extensionmanager_domain_model_extension',
112 'description' => 'List of TER extensions',
113 ],
114 [
115 'name' => 'tx_rsaauth_keys',
116 'description' => 'Login process key storage'
117 ],
118 ];
119
120 $tables = [];
121 foreach ($tableCandidates as $candidate) {
122 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
123 ->getConnectionForTable($candidate['name']);
124 if ($connection->getSchemaManager()->tablesExist([$candidate['name']])) {
125 $candidate['rows'] = $connection->count(
126 '*',
127 $candidate['name'],
128 []
129 );
130 $tables[] = $candidate;
131 }
132 }
133 return $tables;
134 }
135
136 /**
137 * Truncate selected tables
138 *
139 * @return \TYPO3\CMS\Install\Status\StatusInterface
140 */
141 protected function clearSelectedTables()
142 {
143 $clearedTables = [];
144 if (isset($this->postValues['values']) && is_array($this->postValues['values'])) {
145 foreach ($this->postValues['values'] as $tableName => $selected) {
146 if ($selected == 1) {
147 GeneralUtility::makeInstance(ConnectionPool::class)
148 ->getConnectionForTable($tableName)
149 ->truncate($tableName);
150 $clearedTables[] = $tableName;
151 }
152 }
153 }
154 if (!empty($clearedTables)) {
155 /** @var OkStatus $message */
156 $message = GeneralUtility::makeInstance(OkStatus::class);
157 $message->setTitle('Cleared tables');
158 $message->setMessage('List of cleared tables: ' . implode(', ', $clearedTables));
159 } else {
160 /** @var InfoStatus $message */
161 $message = GeneralUtility::makeInstance(InfoStatus::class);
162 $message->setTitle('No tables selected to clear');
163 }
164 return $message;
165 }
166
167 /**
168 * Reset uc field of all be_users to empty string
169 *
170 * @return \TYPO3\CMS\Install\Status\StatusInterface
171 */
172 protected function resetBackendUserUc()
173 {
174 GeneralUtility::makeInstance(ConnectionPool::class)
175 ->getQueryBuilderForTable('be_users')
176 ->update('be_users')
177 ->set('uc', '')
178 ->execute();
179 /** @var OkStatus $message */
180 $message = GeneralUtility::makeInstance(OkStatus::class);
181 $message->setTitle('Reset all backend users preferences');
182 return $message;
183 }
184
185 /**
186 * Data for the typo3temp/ deletion view
187 *
188 * @return array Data array
189 */
190 protected function getTypo3TempStatistics()
191 {
192 $data = [];
193 $pathTypo3Temp = PATH_site . 'typo3temp/';
194 $postValues = $this->postValues['values'];
195
196 $condition = '0';
197 if (isset($postValues['condition'])) {
198 $condition = $postValues['condition'];
199 }
200 $numberOfFilesToDelete = 0;
201 if (isset($postValues['numberOfFiles'])) {
202 $numberOfFilesToDelete = $postValues['numberOfFiles'];
203 }
204 $subDirectory = '';
205 if (isset($postValues['subDirectory'])) {
206 $subDirectory = $postValues['subDirectory'];
207 }
208
209 // Run through files
210 $fileCounter = 0;
211 $deleteCounter = 0;
212 $criteriaMatch = 0;
213 $timeMap = ['day' => 1, 'week' => 7, 'month' => 30];
214 $directory = @dir($pathTypo3Temp . $subDirectory);
215 if (is_object($directory)) {
216 while ($entry = $directory->read()) {
217 $absoluteFile = $pathTypo3Temp . $subDirectory . '/' . $entry;
218 if (@is_file($absoluteFile)) {
219 $ok = false;
220 $fileCounter++;
221 if ($condition) {
222 if (MathUtility::canBeInterpretedAsInteger($condition)) {
223 if (filesize($absoluteFile) > $condition * 1024) {
224 $ok = true;
225 }
226 } else {
227 if (fileatime($absoluteFile) < $GLOBALS['EXEC_TIME'] - (int)$timeMap[$condition] * 60 * 60 * 24) {
228 $ok = true;
229 }
230 }
231 } else {
232 $ok = true;
233 }
234 if ($ok) {
235 $hashPart = substr(basename($absoluteFile), -14, 10);
236 // This is a kind of check that the file being deleted has a 10 char hash in it
237 if (
238 !preg_match('/[^a-f0-9]/', $hashPart)
239 || substr($absoluteFile, -6) === '.cache'
240 || substr($absoluteFile, -4) === '.tbl'
241 || substr($absoluteFile, -4) === '.css'
242 || substr($absoluteFile, -3) === '.js'
243 || substr($absoluteFile, -5) === '.gzip'
244 || substr(basename($absoluteFile), 0, 8) === 'installTool'
245 ) {
246 if ($numberOfFilesToDelete && $deleteCounter < $numberOfFilesToDelete) {
247 $deleteCounter++;
248 unlink($absoluteFile);
249 } else {
250 $criteriaMatch++;
251 }
252 }
253 }
254 }
255 }
256 $directory->close();
257 }
258 $data['numberOfFilesMatchingCriteria'] = $criteriaMatch;
259 $data['numberOfDeletedFiles'] = $deleteCounter;
260
261 if ($deleteCounter > 0) {
262 $message = GeneralUtility::makeInstance(OkStatus::class);
263 $message->setTitle('Deleted ' . $deleteCounter . ' files from typo3temp/' . $subDirectory . '/');
264 $this->actionMessages[] = $message;
265 }
266
267 $data['selectedCondition'] = $condition;
268 $data['numberOfFiles'] = $numberOfFilesToDelete;
269 $data['selectedSubDirectory'] = $subDirectory;
270
271 // Set up sub directory data
272 $data['subDirectories'] = [
273 '' => [
274 'name' => '',
275 'filesNumber' => count(GeneralUtility::getFilesInDir($pathTypo3Temp)),
276 ],
277 ];
278 $directories = dir($pathTypo3Temp);
279 if (is_object($directories)) {
280 while ($entry = $directories->read()) {
281 if (is_dir($pathTypo3Temp . $entry) && $entry !== '..' && $entry !== '.') {
282 $data['subDirectories'][$entry]['name'] = $entry;
283 $data['subDirectories'][$entry]['filesNumber'] = count(GeneralUtility::getFilesInDir($pathTypo3Temp . $entry));
284 $data['subDirectories'][$entry]['selected'] = false;
285 if ($entry === $data['selectedSubDirectory']) {
286 $data['subDirectories'][$entry]['selected'] = true;
287 }
288 }
289 }
290 }
291 $data['numberOfFilesInSelectedDirectory'] = $data['subDirectories'][$data['selectedSubDirectory']]['filesNumber'];
292
293 return $data;
294 }
295
296 /**
297 * Clear processed files
298 *
299 * The sys_file_processedfile table is truncated and the physical files of local storages are deleted.
300 *
301 * @return \TYPO3\CMS\Install\Status\StatusInterface
302 */
303 protected function clearProcessedFiles()
304 {
305 $repository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
306 $failedDeletions = $repository->removeAll();
307 if ($failedDeletions) {
308 /** @var ErrorStatus $message */
309 $message = GeneralUtility::makeInstance(ErrorStatus::class);
310 $message->setTitle('Failed to delete ' . $failedDeletions . ' processed files. See TYPO3 log (by default typo3temp/var/logs/typo3_*.log)');
311 } else {
312 /** @var OkStatus $message */
313 $message = GeneralUtility::makeInstance(OkStatus::class);
314 $message->setTitle('Cleared processed files');
315 }
316
317 return $message;
318 }
319 }