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