xref: /webtrees/app/Services/HousekeepingService.php (revision 4a1f1d433794f86f893b59883147e57af4e94374)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2019 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16declare(strict_types=1);
17
18namespace Fisharebest\Webtrees\Services;
19
20use Exception;
21use Fisharebest\Webtrees\Carbon;
22use Illuminate\Database\Capsule\Manager as DB;
23use League\Flysystem\Filesystem;
24
25/**
26 * Clean up old data, files and folders.
27 */
28class HousekeepingService
29{
30    // This is a list of old files and directories, from earlier versions of webtrees.
31    // git diff 1.7.9..master --name-status | grep ^D
32    private const OLD_PATHS = [
33        // Removed in 1.0.3
34        'themechange.php',
35        // Removed in 1.1.0
36        'addremotelink.php',
37        'addsearchlink.php',
38        'client.php',
39        'dir_editor.php',
40        'editconfig_gedcom.php',
41        'editgedcoms.php',
42        'edit_merge.php',
43        'edit_news.php',
44        'genservice.php',
45        'logs.php',
46        'manageservers.php',
47        'media.php',
48        'module_admin.php',
49        //'modules', // Do not delete - users may have stored custom modules/data here
50        'opensearch.php',
51        'PEAR.php',
52        'pgv_to_wt.php',
53        'places',
54        //'robots.txt', // Do not delete this - it may contain user data
55        'serviceClientTest.php',
56        'siteconfig.php',
57        'SOAP',
58        'themes/clouds/mozilla.css',
59        'themes/clouds/netscape.css',
60        'themes/colors/mozilla.css',
61        'themes/colors/netscape.css',
62        'themes/fab/mozilla.css',
63        'themes/fab/netscape.css',
64        'themes/minimal/mozilla.css',
65        'themes/minimal/netscape.css',
66        'themes/webtrees/mozilla.css',
67        'themes/webtrees/netscape.css',
68        'themes/webtrees/style_rtl.css',
69        'themes/xenea/mozilla.css',
70        'themes/xenea/netscape.css',
71        'uploadmedia.php',
72        'useradmin.php',
73        'webservice',
74        'wtinfo.php',
75        // Removed in 1.1.2
76        'treenav.php',
77        // Removed in 1.2.0
78        'themes/clouds/jquery',
79        'themes/colors/jquery',
80        'themes/fab/jquery',
81        'themes/minimal/jquery',
82        'themes/webtrees/jquery',
83        'themes/xenea/jquery',
84        // Removed in 1.2.2
85        'themes/clouds/chrome.css',
86        'themes/clouds/opera.css',
87        'themes/clouds/print.css',
88        'themes/clouds/style_rtl.css',
89        'themes/colors/chrome.css',
90        'themes/colors/opera.css',
91        'themes/colors/print.css',
92        'themes/colors/style_rtl.css',
93        'themes/fab/chrome.css',
94        'themes/fab/opera.css',
95        'themes/minimal/chrome.css',
96        'themes/minimal/opera.css',
97        'themes/minimal/print.css',
98        'themes/minimal/style_rtl.css',
99        'themes/xenea/chrome.css',
100        'themes/xenea/opera.css',
101        'themes/xenea/print.css',
102        'themes/xenea/style_rtl.css',
103        // Removed in 1.2.3
104        'modules_v2',
105        // Removed in 1.2.4
106        'search_engine.php',
107        'themes/clouds/modules.css',
108        'themes/colors/modules.css',
109        'themes/fab/modules.css',
110        'themes/minimal/modules.css',
111        'themes/webtrees/modules.css',
112        'themes/xenea/modules.css',
113        // Removed in 1.2.5
114        'sidebar.php',
115        // Removed in 1.2.6
116        // Removed in 1.2.7
117        'login_register.php',
118        // Removed in 1.3.0
119        'admin_site_ipaddress.php',
120        'downloadgedcom.php',
121        'export_gedcom.php',
122        'gedcheck.php',
123        'images',
124        // Removed in 1.3.1
125        'imageflush.php',
126        '/lightbox/js/tip_balloon_RTL.js',
127        // Removed in 1.4.0
128        'imageview.php',
129        'media/MediaInfo.txt',
130        'media/thumbs/ThumbsInfo.txt',
131        'themes/webtrees/chrome.css',
132        // Removed in 1.4.2
133        'themes/clouds/jquery-ui-1.10.0',
134        'themes/colors/jquery-ui-1.10.0',
135        'themes/fab/jquery-ui-1.10.0',
136        'themes/minimal/jquery-ui-1.10.0',
137        'themes/webtrees/jquery-ui-1.10.0',
138        'themes/xenea/jquery-ui-1.10.0',
139        // Removed in 1.5.0
140        'themes/clouds/favicon.png',
141        'themes/clouds/images',
142        'themes/clouds/msie.css',
143        'themes/clouds/style.css',
144        'themes/colors/css',
145        'themes/colors/favicon.png',
146        'themes/colors/images',
147        'themes/colors/ipad.css',
148        'themes/colors/msie.css',
149        'themes/fab/favicon.png',
150        'themes/fab/images',
151        'themes/fab/msie.css',
152        'themes/fab/style.css',
153        'themes/minimal/favicon.png',
154        'themes/minimal/images',
155        'themes/minimal/msie.css',
156        'themes/minimal/style.css',
157        'themes/webtrees/favicon.png',
158        'themes/webtrees/images',
159        'themes/webtrees/msie.css',
160        'themes/webtrees/style.css',
161        'themes/xenea/favicon.png',
162        'themes/xenea/images',
163        'themes/xenea/msie.css',
164        'themes/xenea/style.css',
165        // Removed in 1.5.1
166        'themes/clouds/css-1.5.0',
167        'themes/colors/css-1.5.0',
168        'themes/fab/css-1.5.0',
169        'themes/minimal/css-1.5.0',
170        'themes/webtrees/css-1.5.0',
171        'themes/xenea/css-1.5.0',
172        // Removed in 1.5.2
173        'themes/clouds/css-1.5.1',
174        'themes/colors/css-1.5.1',
175        'themes/fab/css-1.5.1',
176        'themes/minimal/css-1.5.1',
177        'themes/webtrees/css-1.5.1',
178        'themes/xenea/css-1.5.1',
179        // Removed in 1.5.3
180        'readme.html',
181        'themes/clouds/css-1.5.2',
182        'themes/colors/css-1.5.2',
183        'themes/fab/css-1.5.2',
184        'themes/minimal/css-1.5.2',
185        'themes/webtrees/css-1.5.2',
186        'themes/xenea/css-1.5.2',
187        // Removed in 1.6.0
188        'downloadbackup.php',
189        'site-php-version.php',
190        'themes/clouds/css-1.5.3',
191        'themes/colors/css-1.5.3',
192        'themes/fab/css-1.5.3',
193        'themes/minimal/css-1.5.3',
194        'themes/webtrees/css-1.5.3',
195        'themes/xenea/css-1.5.3',
196        // Removed in 1.6.2
197        'themes/clouds/jquery-ui-1.10.3',
198        'themes/colors/css-1.6.0',
199        'themes/colors/jquery-ui-1.10.3',
200        'themes/fab/css-1.6.0',
201        'themes/fab/jquery-ui-1.10.3',
202        'themes/minimal/css-1.6.0',
203        'themes/minimal/jquery-ui-1.10.3',
204        'themes/webtrees/css-1.6.0',
205        'themes/webtrees/jquery-ui-1.10.3',
206        'themes/xenea/css-1.6.0',
207        'themes/xenea/jquery-ui-1.10.3',
208        // Removed in 1.7.0
209        'admin_site_other.php',
210        'js',
211        'library',
212        'save.php',
213        'themes/clouds/css-1.6.2',
214        'themes/clouds/templates',
215        'themes/clouds/header.php',
216        'themes/clouds/footer.php',
217        'themes/colors/css-1.6.2',
218        'themes/colors/templates',
219        'themes/colors/header.php',
220        'themes/colors/footer.php',
221        'themes/fab/css-1.6.2',
222        'themes/fab/templates',
223        'themes/fab/header.php',
224        'themes/fab/footer.php',
225        'themes/minimal/css-1.6.2',
226        'themes/minimal/templates',
227        'themes/minimal/header.php',
228        'themes/minimal/footer.php',
229        'themes/webtrees/css-1.6.2',
230        'themes/webtrees/templates',
231        'themes/webtrees/header.php',
232        'themes/webtrees/footer.php',
233        'themes/xenea/css-1.6.2',
234        'themes/xenea/templates',
235        'themes/xenea/header.php',
236        'themes/xenea/footer.php',
237        // Removed in 1.7.2
238        'assets/js-1.7.0',
239        // Removed in 1.7.4
240        'assets/js-1.7.2',
241        'themes/clouds/css-1.7.0',
242        'themes/colors/css-1.7.0',
243        'themes/fab/css-1.7.0',
244        'themes/minimal/css-1.7.0',
245        'themes/webtrees/css-1.7.0',
246        'themes/xenea/css-1.7.0',
247        // Removed in 1.7.5
248        'themes/clouds/css-1.7.4',
249        'themes/colors/css-1.7.4',
250        'themes/fab/css-1.7.4',
251        'themes/minimal/css-1.7.4',
252        'themes/webtrees/css-1.7.4',
253        'themes/xenea/css-1.7.4',
254        // Removed in 1.7.7
255        'assets/js-1.7.4',
256        // Removed in 1.7.8
257        'themes/clouds/css-1.7.5',
258        'themes/colors/css-1.7.5',
259        'themes/fab/css-1.7.5',
260        'themes/minimal/css-1.7.5',
261        'themes/webtrees/css-1.7.5',
262        'themes/xenea/css-1.7.5',
263        // Removed in 2.0.0
264        'action.php',
265        'addmedia.php',
266        'addmin.php',
267        'admin_media.php',
268        'admin_media_upload.php',
269        'admin_module_blocks.php',
270        'admin_module_charts.php',
271        'admin_module_menus.php',
272        'admin_module_reports.php',
273        'admin_module_sidebar.php',
274        'admin_module_tabs.php',
275        'admin_modules.php',
276        'admin_pgv_to_wt.php',
277        'admin_site_access.php',
278        'admin_site_change.php',
279        'admin_site_clean.php',
280        'admin_site_config.php',
281        'admin_site_info.php',
282        'admin_site_logs.php',
283        'admin_site_merge.php',
284        'admin_site_readme.php',
285        'admin_site_upgrade.php',
286        'admin_trees_check.php',
287        'admin_trees_config.php',
288        'admin_trees_download.php',
289        'admin_trees_duplicates.php',
290        'admin_trees_export.php',
291        'admin_trees_manage.php',
292        'admin_trees_merge.php',
293        'admin_trees_places.php',
294        'admin_trees_renumber.php',
295        'admin_trees_unconnected.php',
296        'admin_users.php',
297        'admin_users_bulk.php',
298        'ancestry.php',
299        'app/Controller',
300        'app/HitCounter.php',
301        'app/Module/ClippingsCart/ClippingsCartController.php',
302        'app/Module/FamiliesSidebarModule.php',
303        'app/Module/FamilyTreeFavorites',
304        'app/Module/GoogleMaps',
305        'app/Module/IndividualSidebarModule.php',
306        'app/Module/PageMenuModule.php',
307        'app/Query',
308        'app/SpecialChars',
309        'assets/js-1.7.7',
310        'assets/js-1.7.9',
311        'autocomplete.php',
312        'block_edit.php',
313        'branches.php',
314        'calendar.php',
315        'compact.php',
316        'data/html_purifier_cache',
317        'descendancy.php',
318        'editnews.php',
319        'edituser.php',
320        'edit_changes.php',
321        'edit_interface.php',
322        'expand_view.php',
323        'familybook.php',
324        'famlist.php',
325        'fanchart.php',
326        'find.php',
327        'help_text.php',
328        'hourglass.php',
329        'hourglass_ajax.php',
330        'import.php',
331        'includes',
332        'index_edit.php',
333        'indilist.php',
334        'inverselink.php',
335        'language',
336        'lifespan.php',
337        'login.php',
338        'logout.php',
339        'mediafirewall.php',
340        'medialist.php',
341        'message.php',
342        'module.php',
343        'modules_v3',
344        'notelist.php',
345        'packages',
346        'pedigree.php',
347        'relationship.php',
348        'repolist.php',
349        'reportengine.php',
350        'search.php',
351        'search_advanced.php',
352        'site-offline.php',
353        'site-unavailable.php',
354        'sourcelist.php',
355        'statistics.php',
356        'statisticsplot.php',
357        'themes/_administration',
358        'themes/_custom',
359        'themes/clouds/css-1.7.8',
360        'themes/clouds/jquery-ui-1.11.2',
361        'themes/colors/css-1.7.8',
362        'themes/colors/jquery-ui-1.11.2',
363        'themes/fab/css-1.7.8',
364        'themes/fab/jquery-ui-1.11.2',
365        'themes/minimal/css-1.7.8',
366        'themes/minimal/jquery-ui-1.11.2',
367        'themes/webtrees/css-1.7.8',
368        'themes/webtrees/jquery-ui-1.11.2',
369        'themes/xenea/css-1.7.8',
370        'themes/xenea/jquery-ui-1.11.2',
371        'timeline.php',
372    ];
373
374    /**
375     * Delete files and folders that belonged to an earlier version of webtrees.
376     * Return a list of those that we could not delete.
377     *
378     * @param Filesystem $filesystem
379     *
380     * @return array
381     */
382    public function deleteOldWebtreesFiles(Filesystem $filesystem): array
383    {
384        $paths_to_delete = [];
385
386        foreach (self::OLD_PATHS as $path) {
387            if (!$this->deleteFileOrFolder($filesystem, $path)) {
388                $paths_to_delete[] = $path;
389            }
390        }
391
392        return $paths_to_delete;
393    }
394
395    /**
396     * Delete old cache files.
397     *
398     * @param Filesystem $filesystem
399     * @param string     $path
400     * @param int        $max_age    Seconds
401     *
402     * @return void
403     */
404    public function deleteOldFiles(Filesystem $filesystem, string $path, int $max_age): void
405    {
406        $list = $filesystem->listContents($path, true);
407
408        $timestamp = Carbon::now()->unix();
409
410        foreach ($list as $metadata) {
411            if ($metadata['timestamp'] ?? $timestamp < $timestamp - $max_age) {
412                $this->deleteFileOrFolder($filesystem, $metadata['path']);
413            }
414        }
415    }
416
417    /**
418     * @param int $max_age_in_seconds
419     *
420     * @return void
421     */
422    public function deleteOldLogs(int $max_age_in_seconds): void
423    {
424        $timestamp = Carbon::now()->subSeconds($max_age_in_seconds);
425
426        DB::table('log')
427            ->whereIn('log_type', ['error', 'media'])
428            ->where('log_time', '<', $timestamp)
429            ->delete();
430    }
431
432    /**
433     * @param int $max_age_in_seconds
434     *
435     * @return void
436     */
437    public function deleteOldSessions(int $max_age_in_seconds): void
438    {
439        $timestamp = Carbon::now()->subSeconds($max_age_in_seconds);
440
441        DB::table('session')
442            ->where('session_time', '<', $timestamp)
443            ->delete();
444    }
445
446    /**
447     * Delete a file or folder, if we can.
448     *
449     * @param Filesystem $filesystem
450     * @param string     $path
451     *
452     * @return bool
453     */
454    private function deleteFileOrFolder(Filesystem $filesystem, string $path): bool
455    {
456        if ($filesystem->has($path)) {
457            try {
458                $metadata = $filesystem->getMetadata($path);
459
460                if ($metadata['type'] === 'dir') {
461                    $filesystem->deleteDir($path);
462                }
463
464                if ($metadata['type'] === 'file') {
465                    $filesystem->delete($path);
466                }
467            } catch (Exception $ex) {
468                return false;
469            }
470        }
471
472        return true;
473    }
474}
475