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 Carbon\Carbon; 21use Fisharebest\Webtrees\Site; 22use Fisharebest\Webtrees\Webtrees; 23use GuzzleHttp\Client; 24use GuzzleHttp\Exception\RequestException; 25use Symfony\Component\HttpFoundation\Response; 26 27/** 28 * Automatic upgrades. 29 */ 30class UpgradeService 31{ 32 // Only check the webtrees server infrequently. 33 private const CHECK_FOR_UPDATE_INTERVAL = 24 * 60 * 60; 34 35 // Fetch information about upgrades from here. 36 // Note: earlier versions of webtrees used svn.webtrees.net, so we must maintain both URLs. 37 private const UPDATE_URL = 'https://dev.webtrees.net/build/latest-version.txt'; 38 39 // If the update server doesn't respond after this time, give up. 40 private const HTTP_TIMEOUT = 3.0; 41 42 /** 43 * @return bool 44 */ 45 public function isUpgradeAvailable(): bool 46 { 47 // If the latest version is unavailable, we will have an empty sting which equates to version 0. 48 49 return version_compare(Webtrees::VERSION, $this->fetchLatestVersion()) < 0; 50 } 51 52 /** 53 * What is the latest version of webtrees. 54 * 55 * @return string 56 */ 57 public function latestVersion(): string 58 { 59 $latest_version = $this->fetchLatestVersion(); 60 61 [$version] = explode('|', $latest_version); 62 63 return $version; 64 } 65 66 /** 67 * Where can we download the latest version of webtrees. 68 * 69 * @return string 70 */ 71 public function downloadUrl(): string 72 { 73 $latest_version = $this->fetchLatestVersion(); 74 75 [, , $url] = explode('|', $latest_version . '||'); 76 77 return $url; 78 } 79 80 /** 81 * Check with the webtrees.net server for the latest version of webtrees. 82 * Fetching the remote file can be slow, so check infrequently, and cache the result. 83 * Pass the current versions of webtrees, PHP and MySQL, as the response 84 * may be different for each. The server logs are used to generate 85 * installation statistics which can be found at http://dev.webtrees.net/statistics.html 86 * 87 * @return string 88 */ 89 private function fetchLatestVersion(): string 90 { 91 $last_update_timestamp = (int) Site::getPreference('LATEST_WT_VERSION_TIMESTAMP'); 92 93 $current_timestamp = Carbon::now()->timestamp; 94 95 if ($last_update_timestamp < $current_timestamp - self::CHECK_FOR_UPDATE_INTERVAL) { 96 try { 97 $client = new Client([ 98 'timeout' => self::HTTP_TIMEOUT, 99 ]); 100 101 $response = $client->get(self::UPDATE_URL, [ 102 'query' => $this->serverParameters(), 103 ]); 104 105 if ($response->getStatusCode() === Response::HTTP_OK) { 106 Site::setPreference('LATEST_WT_VERSION', $response->getBody()->getContents()); 107 Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', (string) $current_timestamp); 108 } 109 } catch (RequestException $ex) { 110 // Can't connect to the server? 111 // Use the existing information about latest versions. 112 } 113 } 114 115 return Site::getPreference('LATEST_WT_VERSION'); 116 } 117 118 /** 119 * The upgrade server needs to know a little about this server. 120 */ 121 private function serverParameters(): array 122 { 123 $operating_system = DIRECTORY_SEPARATOR === '/' ? 'u' : 'w'; 124 125 return [ 126 'w' => Webtrees::VERSION, 127 'p' => PHP_VERSION, 128 'o' => $operating_system, 129 ]; 130 } 131} 132