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