1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 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 */ 16namespace Fisharebest\Webtrees\Services; 17 18use Exception; 19use Fisharebest\Webtrees\Database; 20use League\Flysystem\Filesystem; 21 22/** 23 * Clean up old data, files and folders. 24 */ 25class HousekeepingService 26{ 27 // This is a list of old files and directories, from earlier versions of webtrees. 28 // git diff 1.7.9..master --name-status | grep ^D 29 const OLD_PATHS = [ 30 // Removed in 1.0.2 31 'language/en.mo', 32 // Removed in 1.0.3 33 'themechange.php', 34 // Removed in 1.1.0 35 'addremotelink.php', 36 'addsearchlink.php', 37 'client.php', 38 'dir_editor.php', 39 'editconfig_gedcom.php', 40 'editgedcoms.php', 41 'edit_merge.php', 42 'edit_news.php', 43 'genservice.php', 44 'logs.php', 45 'manageservers.php', 46 'media.php', 47 'module_admin.php', 48 //WT_ROOT.'modules', // Do not delete - users may have stored custom modules/data here 49 'opensearch.php', 50 'PEAR.php', 51 'pgv_to_wt.php', 52 'places', 53 //WT_ROOT.'robots.txt', // Do not delete this - it may contain user data 54 'serviceClientTest.php', 55 'siteconfig.php', 56 'SOAP', 57 'themes/clouds/mozilla.css', 58 'themes/clouds/netscape.css', 59 'themes/colors/mozilla.css', 60 'themes/colors/netscape.css', 61 'themes/fab/mozilla.css', 62 'themes/fab/netscape.css', 63 'themes/minimal/mozilla.css', 64 'themes/minimal/netscape.css', 65 'themes/webtrees/mozilla.css', 66 'themes/webtrees/netscape.css', 67 'themes/webtrees/style_rtl.css', 68 'themes/xenea/mozilla.css', 69 'themes/xenea/netscape.css', 70 'uploadmedia.php', 71 'useradmin.php', 72 'webservice', 73 'wtinfo.php', 74 // Removed in 1.1.2 75 'treenav.php', 76 // Removed in 1.2.0 77 'themes/clouds/jquery', 78 'themes/colors/jquery', 79 'themes/fab/jquery', 80 'themes/minimal/jquery', 81 'themes/webtrees/jquery', 82 'themes/xenea/jquery', 83 // Removed in 1.2.2 84 'themes/clouds/chrome.css', 85 'themes/clouds/opera.css', 86 'themes/clouds/print.css', 87 'themes/clouds/style_rtl.css', 88 'themes/colors/chrome.css', 89 'themes/colors/opera.css', 90 'themes/colors/print.css', 91 'themes/colors/style_rtl.css', 92 'themes/fab/chrome.css', 93 'themes/fab/opera.css', 94 'themes/minimal/chrome.css', 95 'themes/minimal/opera.css', 96 'themes/minimal/print.css', 97 'themes/minimal/style_rtl.css', 98 'themes/xenea/chrome.css', 99 'themes/xenea/opera.css', 100 'themes/xenea/print.css', 101 'themes/xenea/style_rtl.css', 102 // Removed in 1.2.3 103 //WT_ROOT.'modules_v2', // Do not delete - users may have stored custom modules/data here 104 // Removed in 1.2.4 105 'modules_v3/gedcom_favorites/help_text.php', 106 'modules_v3/GEDFact_assistant/_MEDIA/media_3_find.php', 107 'modules_v3/GEDFact_assistant/_MEDIA/media_3_search_add.php', 108 'modules_v3/GEDFact_assistant/_MEDIA/media_5_input.js', 109 'modules_v3/GEDFact_assistant/_MEDIA/media_5_input.php', 110 'modules_v3/GEDFact_assistant/_MEDIA/media_7_parse_addLinksTbl.php', 111 'modules_v3/GEDFact_assistant/_MEDIA/media_query_1a.php', 112 'modules_v3/GEDFact_assistant/_MEDIA/media_query_2a.php', 113 'modules_v3/GEDFact_assistant/_MEDIA/media_query_3a.php', 114 'modules_v3/lightbox/css/album_page_RTL2.css', 115 'modules_v3/lightbox/css/album_page_RTL.css', 116 'modules_v3/lightbox/css/album_page_RTL_ff.css', 117 'modules_v3/lightbox/css/clearbox_music.css', 118 'modules_v3/lightbox/css/clearbox_music_RTL.css', 119 'modules_v3/user_favorites/db_schema', 120 'modules_v3/user_favorites/help_text.php', 121 'search_engine.php', 122 'themes/clouds/modules.css', 123 'themes/colors/modules.css', 124 'themes/fab/modules.css', 125 'themes/minimal/modules.css', 126 'themes/webtrees/modules.css', 127 'themes/xenea/modules.css', 128 // Removed in 1.2.5 129 'modules_v3/clippings/index.php', 130 'modules_v3/googlemap/css/googlemap_style.css', 131 'modules_v3/googlemap/css/wt_v3_places_edit.css', 132 'modules_v3/googlemap/index.php', 133 'modules_v3/lightbox/index.php', 134 'modules_v3/recent_changes/help_text.php', 135 'modules_v3/todays_events/help_text.php', 136 'sidebar.php', 137 // Removed in 1.2.6 138 'modules_v3/sitemap/admin_index.php', 139 'modules_v3/sitemap/help_text.php', 140 'modules_v3/tree/css/styles', 141 'modules_v3/tree/css/treebottom.gif', 142 'modules_v3/tree/css/treebottomleft.gif', 143 'modules_v3/tree/css/treebottomright.gif', 144 'modules_v3/tree/css/tree.jpg', 145 'modules_v3/tree/css/treeleft.gif', 146 'modules_v3/tree/css/treeright.gif', 147 'modules_v3/tree/css/treetop.gif', 148 'modules_v3/tree/css/treetopleft.gif', 149 'modules_v3/tree/css/treetopright.gif', 150 'modules_v3/tree/css/treeview_print.css', 151 'modules_v3/tree/help_text.php', 152 'modules_v3/tree/images/print.png', 153 // Removed in 1.2.7 154 'login_register.php', 155 'modules_v3/top10_givnnames/help_text.php', 156 'modules_v3/top10_surnames/help_text.php', 157 // Removed in 1.3.0 158 'admin_site_ipaddress.php', 159 'downloadgedcom.php', 160 'export_gedcom.php', 161 'gedcheck.php', 162 'images', 163 'modules_v3/googlemap/admin_editconfig.php', 164 'modules_v3/googlemap/admin_placecheck.php', 165 'modules_v3/googlemap/flags.php', 166 'modules_v3/googlemap/images/pedigree_map.gif', 167 'modules_v3/googlemap/pedigree_map.php', 168 'modules_v3/lightbox/admin_config.php', 169 'modules_v3/lightbox/album.php', 170 'modules_v3/tree/css/vline.jpg', 171 // Removed in 1.3.1 172 'imageflush.php', 173 'modules_v3/googlemap/wt_v3_pedigree_map.js.php', 174 'modules_v3/lightbox/js/tip_balloon_RTL.js', 175 // Removed in 1.3.2 176 'modules_v3/address_report', 177 'modules_v3/lightbox/functions/lb_horiz_sort.php', 178 'modules_v3/random_media/help_text.php', 179 // Removed in 1.4.0 180 'imageview.php', 181 'media/MediaInfo.txt', 182 'media/thumbs/ThumbsInfo.txt', 183 'modules_v3/GEDFact_assistant/css/media_0_inverselink.css', 184 'modules_v3/lightbox/help_text.php', 185 'modules_v3/lightbox/images/blank.gif', 186 'modules_v3/lightbox/images/close_1.gif', 187 'modules_v3/lightbox/images/image_add.gif', 188 'modules_v3/lightbox/images/image_copy.gif', 189 'modules_v3/lightbox/images/image_delete.gif', 190 'modules_v3/lightbox/images/image_edit.gif', 191 'modules_v3/lightbox/images/image_link.gif', 192 'modules_v3/lightbox/images/images.gif', 193 'modules_v3/lightbox/images/image_view.gif', 194 'modules_v3/lightbox/images/loading.gif', 195 'modules_v3/lightbox/images/next.gif', 196 'modules_v3/lightbox/images/nextlabel.gif', 197 'modules_v3/lightbox/images/norm_2.gif', 198 'modules_v3/lightbox/images/overlay.png', 199 'modules_v3/lightbox/images/prev.gif', 200 'modules_v3/lightbox/images/prevlabel.gif', 201 'modules_v3/lightbox/images/private.gif', 202 'modules_v3/lightbox/images/slideshow.jpg', 203 'modules_v3/lightbox/images/transp80px.gif', 204 'modules_v3/lightbox/images/zoom_1.gif', 205 'modules_v3/lightbox/js', 206 'modules_v3/lightbox/music', 207 'modules_v3/lightbox/pic', 208 'themes/webtrees/chrome.css', 209 // Removed in 1.4.1 210 'modules_v3/lightbox/images/image_edit.png', 211 'modules_v3/lightbox/images/image_view.png', 212 // Removed in 1.4.2 213 'modules_v3/lightbox/images/image_view.png', 214 'modules_v3/top10_pageviews/help_text.php', 215 'themes/clouds/jquery-ui-1.10.0', 216 'themes/colors/jquery-ui-1.10.0', 217 'themes/fab/jquery-ui-1.10.0', 218 'themes/minimal/jquery-ui-1.10.0', 219 'themes/webtrees/jquery-ui-1.10.0', 220 'themes/xenea/jquery-ui-1.10.0', 221 // Removed in 1.5.0 222 'modules_v3/GEDFact_assistant/_CENS/census_note_decode.php', 223 'modules_v3/GEDFact_assistant/_CENS/census_asst_date.php', 224 'modules_v3/googlemap/wt_v3_googlemap.js.php', 225 'modules_v3/lightbox/functions/lightbox_print_media.php', 226 'modules_v3/upcoming_events/help_text.php', 227 'modules_v3/stories/help_text.php', 228 'modules_v3/user_messages/help_text.php', 229 'themes/clouds/favicon.png', 230 'themes/clouds/images', 231 'themes/clouds/msie.css', 232 'themes/clouds/style.css', 233 'themes/colors/css', 234 'themes/colors/favicon.png', 235 'themes/colors/images', 236 'themes/colors/ipad.css', 237 'themes/colors/msie.css', 238 'themes/fab/favicon.png', 239 'themes/fab/images', 240 'themes/fab/msie.css', 241 'themes/fab/style.css', 242 'themes/minimal/favicon.png', 243 'themes/minimal/images', 244 'themes/minimal/msie.css', 245 'themes/minimal/style.css', 246 'themes/webtrees/favicon.png', 247 'themes/webtrees/images', 248 'themes/webtrees/msie.css', 249 'themes/webtrees/style.css', 250 'themes/xenea/favicon.png', 251 'themes/xenea/images', 252 'themes/xenea/msie.css', 253 'themes/xenea/style.css', 254 // Removed in 1.5.1 255 'themes/clouds/css-1.5.0', 256 'themes/colors/css-1.5.0', 257 'themes/fab/css-1.5.0', 258 'themes/minimal/css-1.5.0', 259 'themes/webtrees/css-1.5.0', 260 'themes/xenea/css-1.5.0', 261 // Removed in 1.5.2 262 'themes/clouds/css-1.5.1', 263 'themes/colors/css-1.5.1', 264 'themes/fab/css-1.5.1', 265 'themes/minimal/css-1.5.1', 266 'themes/webtrees/css-1.5.1', 267 'themes/xenea/css-1.5.1', 268 // Removed in 1.5.3 269 'modules_v3/GEDFact_assistant/_CENS/census_asst_help.php', 270 'modules_v3/googlemap/admin_places.php', 271 'modules_v3/googlemap/defaultconfig.php', 272 'modules_v3/googlemap/googlemap.php', 273 'modules_v3/googlemap/placehierarchy.php', 274 'modules_v3/googlemap/places_edit.php', 275 'modules_v3/googlemap/util.js', 276 'modules_v3/googlemap/wt_v3_places_edit.js.php', 277 'modules_v3/googlemap/wt_v3_places_edit_overlays.js.php', 278 'modules_v3/googlemap/wt_v3_street_view.php', 279 'readme.html', 280 'themes/clouds/css-1.5.2', 281 'themes/colors/css-1.5.2', 282 'themes/fab/css-1.5.2', 283 'themes/minimal/css-1.5.2', 284 'themes/webtrees/css-1.5.2', 285 'themes/xenea/css-1.5.2', 286 // Removed in 1.6.0 287 'downloadbackup.php', 288 'modules_v3/ckeditor/ckeditor-4.3.2-custom', 289 'site-php-version.php', 290 'themes/clouds/css-1.5.3', 291 'themes/colors/css-1.5.3', 292 'themes/fab/css-1.5.3', 293 'themes/minimal/css-1.5.3', 294 'themes/webtrees/css-1.5.3', 295 'themes/xenea/css-1.5.3', 296 // Removed in 1.6.2 297 'themes/clouds/jquery-ui-1.10.3', 298 'themes/colors/css-1.6.0', 299 'themes/colors/jquery-ui-1.10.3', 300 'themes/fab/css-1.6.0', 301 'themes/fab/jquery-ui-1.10.3', 302 'themes/minimal/css-1.6.0', 303 'themes/minimal/jquery-ui-1.10.3', 304 'themes/webtrees/css-1.6.0', 305 'themes/webtrees/jquery-ui-1.10.3', 306 'themes/xenea/css-1.6.0', 307 'themes/xenea/jquery-ui-1.10.3', 308 // Removed in 1.7.0 309 'admin_site_other.php', 310 'js', 311 'language/en_GB.mo', 312 // Replaced with en-GB.mo 313 'language/en_US.mo', 314 // Replaced with en-US.mo 315 'language/pt_BR.mo', 316 // Replaced with pt-BR.mo 317 'language/zh_CN.mo', 318 // Replaced with zh-Hans.mo 319 'language/extra', 320 'library', 321 'modules_v3/batch_update/admin_batch_update.php', 322 'modules_v3/batch_update/plugins', 323 'modules_v3/charts/help_text.php', 324 'modules_v3/ckeditor/ckeditor-4.4.1-custom', 325 'modules_v3/clippings/clippings_ctrl.php', 326 'modules_v3/clippings/help_text.php', 327 'modules_v3/faq/help_text.php', 328 'modules_v3/gedcom_favorites/db_schema', 329 'modules_v3/gedcom_news/db_schema', 330 'modules_v3/googlemap/db_schema', 331 'modules_v3/googlemap/help_text.php', 332 'modules_v3/html/help_text.php', 333 'modules_v3/logged_in/help_text.php', 334 'modules_v3/review_changes/help_text.php', 335 'modules_v3/todo/help_text.php', 336 'modules_v3/tree/class_treeview.php', 337 'modules_v3/user_blog/db_schema', 338 'modules_v3/yahrzeit/help_text.php', 339 'save.php', 340 'themes/clouds/css-1.6.2', 341 'themes/clouds/templates', 342 'themes/clouds/header.php', 343 'themes/clouds/footer.php', 344 'themes/colors/css-1.6.2', 345 'themes/colors/templates', 346 'themes/colors/header.php', 347 'themes/colors/footer.php', 348 'themes/fab/css-1.6.2', 349 'themes/fab/templates', 350 'themes/fab/header.php', 351 'themes/fab/footer.php', 352 'themes/minimal/css-1.6.2', 353 'themes/minimal/templates', 354 'themes/minimal/header.php', 355 'themes/minimal/footer.php', 356 'themes/webtrees/css-1.6.2', 357 'themes/webtrees/templates', 358 'themes/webtrees/header.php', 359 'themes/webtrees/footer.php', 360 'themes/xenea/css-1.6.2', 361 'themes/xenea/templates', 362 'themes/xenea/header.php', 363 'themes/xenea/footer.php', 364 // Removed in 1.7.2 365 'assets/js-1.7.0', 366 // Removed in 1.7.3 367 'modules_v3/GEDFact_assistant/census/date.js', 368 'modules_v3/GEDFact_assistant/census/dynamicoptionlist.js', 369 // Removed in 1.7.4 370 'assets/js-1.7.2', 371 'themes/clouds/css-1.7.0', 372 'themes/colors/css-1.7.0', 373 'themes/fab/css-1.7.0', 374 'themes/minimal/css-1.7.0', 375 'themes/webtrees/css-1.7.0', 376 'themes/xenea/css-1.7.0', 377 // Removed in 1.7.5 378 'themes/clouds/css-1.7.4', 379 'themes/colors/css-1.7.4', 380 'themes/fab/css-1.7.4', 381 'themes/minimal/css-1.7.4', 382 'themes/webtrees/css-1.7.4', 383 'themes/xenea/css-1.7.4', 384 // Removed in 1.7.7 385 'assets/js-1.7.4', 386 'modules_v3/googlemap/images/css_sprite_facts.png', 387 'modules_v3/googlemap/images/flag_shadow.png', 388 'modules_v3/googlemap/images/shadow-left-large.png', 389 'modules_v3/googlemap/images/shadow-left-small.png', 390 'modules_v3/googlemap/images/shadow-right-large.png', 391 'modules_v3/googlemap/images/shadow-right-small.png', 392 'modules_v3/googlemap/images/shadow50.png', 393 'modules_v3/googlemap/images/transparent-left-large.png', 394 'modules_v3/googlemap/images/transparent-left-small.png', 395 'modules_v3/googlemap/images/transparent-right-large.png', 396 'modules_v3/googlemap/images/transparent-right-small.png', 397 // Removed in 1.7.8 398 'themes/clouds/css-1.7.5', 399 'themes/colors/css-1.7.5', 400 'themes/fab/css-1.7.5', 401 'themes/minimal/css-1.7.5', 402 'themes/webtrees/css-1.7.5', 403 'themes/xenea/css-1.7.5', 404 // Removed in 2.0.0 405 'action.php', 406 'addmedia.php', 407 'addmin.php', 408 'admin_media.php', 409 'admin_media_upload.php', 410 'admin_module_blocks.php', 411 'admin_module_charts.php', 412 'admin_module_menus.php', 413 'admin_module_reports.php', 414 'admin_module_sidebar.php', 415 'admin_module_tabs.php', 416 'admin_modules.php', 417 'admin_pgv_to_wt.php', 418 'admin_site_access.php', 419 'admin_site_change.php', 420 'admin_site_clean.php', 421 'admin_site_config.php', 422 'admin_site_info.php', 423 'admin_site_logs.php', 424 'admin_site_merge.php', 425 'admin_site_readme.php', 426 'admin_site_upgrade.php', 427 'admin_trees_check.php', 428 'admin_trees_config.php', 429 'admin_trees_download.php', 430 'admin_trees_duplicates.php', 431 'admin_trees_export.php', 432 'admin_trees_manage.php', 433 'admin_trees_merge.php', 434 'admin_trees_places.php', 435 'admin_trees_renumber.php', 436 'admin_trees_unconnected.php', 437 'admin_users.php', 438 'admin_users_bulk.php', 439 'ancestry.php', 440 'app/Controller', 441 'app/HitCounter.php', 442 'app/Module/ClippingsCart/ClippingsCartController.php', 443 'app/Module/FamiliesSidebarModule.php', 444 'app/Module/FamilyTreeFavorites', 445 'app/Module/GoogleMaps', 446 'app/Module/IndividualSidebarModule.php', 447 'app/Module/PageMenuModule.php', 448 'app/Query', 449 'app/SpecialChars', 450 'assets/js-1.7.7', 451 'assets/js-1.7.9', 452 'autocomplete.php', 453 'block_edit.php', 454 'branches.php', 455 'calendar.php', 456 'compact.php', 457 'data/html_purifier_cache', 458 'descendancy.php', 459 'editnews.php', 460 'edituser.php', 461 'edit_changes.php', 462 'edit_interface.php', 463 'expand_view.php', 464 'familybook.php', 465 'famlist.php', 466 'fanchart.php', 467 'find.php', 468 'help_text.php', 469 'hourglass.php', 470 'hourglass_ajax.php', 471 'import.php', 472 'includes', 473 'index_edit.php', 474 'indilist.php', 475 'inverselink.php', 476 'lifespan.php', 477 'login.php', 478 'logout.php', 479 'mediafirewall.php', 480 'medialist.php', 481 'message.php', 482 'module.php', 483 'notelist.php', 484 'packages', 485 'pedigree.php', 486 'relationship.php', 487 'repolist.php', 488 'reportengine.php', 489 'search.php', 490 'search_advanced.php', 491 'site-offline.php', 492 'site-unavailable.php', 493 'sourcelist.php', 494 'statistics.php', 495 'statisticsplot.php', 496 'themes/_administration', 497 'themes/_custom', 498 'themes/clouds/css-1.7.8', 499 'themes/clouds/jquery-ui-1.11.2', 500 'themes/colors/css-1.7.8', 501 'themes/colors/jquery-ui-1.11.2', 502 'themes/fab/css-1.7.8', 503 'themes/fab/jquery-ui-1.11.2', 504 'themes/minimal/css-1.7.8', 505 'themes/minimal/jquery-ui-1.11.2', 506 'themes/webtrees/css-1.7.8', 507 'themes/webtrees/jquery-ui-1.11.2', 508 'themes/xenea/css-1.7.8', 509 'themes/xenea/jquery-ui-1.11.2', 510 'timeline.php', 511 ]; 512 513 /** 514 * Delete files and folders that belonged to an earlier version of webtrees. 515 * Return a list of those that we could not delete. 516 * 517 * @param Filesystem $filesystem 518 * 519 * @return array 520 */ 521 public function deleteOldWebtreesFiles(Filesystem $filesystem): array 522 { 523 $paths_to_delete = []; 524 525 foreach (self::OLD_PATHS as $path) { 526 if (!$this->deleteFileOrFolder($filesystem, $path)) { 527 $paths_to_delete[] = $path; 528 } 529 } 530 531 return $paths_to_delete; 532 } 533 534 /** 535 * Delete old cache files. 536 * 537 * @param Filesystem $filesystem 538 * @param string $path_to_cache 539 * @param int $max_age_in_seconds 540 * 541 * @return void 542 */ 543 public function deleteOldCacheFiles(Filesystem $filesystem, string $path_to_cache, int $max_age_in_seconds) 544 { 545 $list = $filesystem->listContents($path_to_cache, true); 546 547 foreach ($list as $metadata) { 548 if ($metadata['timestamp'] ?? WT_TIMESTAMP < WT_TIMESTAMP - $max_age_in_seconds) { 549 $this->deleteFileOrFolder($filesystem, $metadata['path']); 550 } 551 } 552 } 553 554 /** 555 * @param int $max_age_in_seconds 556 * 557 * @return void 558 */ 559 public function deleteOldLogs(int $max_age_in_seconds) 560 { 561 if (Database::isConnected()) { 562 Database::prepare( 563 "DELETE FROM `##log` WHERE log_type IN ('error', 'media') AND log_time < FROM_UNIXTIME(:timestamp)" 564 )->execute([ 565 'timestamp' => WT_TIMESTAMP - $max_age_in_seconds 566 ]); 567 } 568 } 569 570 /** 571 * @param int $max_age_in_seconds 572 * 573 * @return void 574 */ 575 public function deleteOldSessions(int $max_age_in_seconds) 576 { 577 if (Database::isConnected()) { 578 Database::prepare( 579 "DELETE FROM `##session` WHERE session_time < FROM_UNIXTIME(:timestamp)" 580 )->execute([ 581 'timestamp' => WT_TIMESTAMP - $max_age_in_seconds 582 ]); 583 } 584 } 585 586 /** 587 * Delete a file or folder, if we can. 588 * 589 * @param Filesystem $filesystem 590 * @param string $path 591 * 592 * @return bool 593 */ 594 private function deleteFileOrFolder(Filesystem $filesystem, string $path): bool 595 { 596 if ($filesystem->has($path)) { 597 try { 598 $metadata = $filesystem->getMetadata($path); 599 600 if ($metadata['type'] === 'dir') { 601 $filesystem->deleteDir($path); 602 } 603 604 if ($metadata['type'] === 'file') { 605 $filesystem->delete($path); 606 } 607 } catch (Exception $ex) { 608 return false; 609 } 610 } 611 612 return true; 613 } 614} 615