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