10d11ac7eSGreg Roach<?php 20d11ac7eSGreg Roach/** 30d11ac7eSGreg Roach * webtrees: online genealogy 40d11ac7eSGreg Roach * Copyright (C) 2018 webtrees development team 50d11ac7eSGreg Roach * This program is free software: you can redistribute it and/or modify 60d11ac7eSGreg Roach * it under the terms of the GNU General Public License as published by 70d11ac7eSGreg Roach * the Free Software Foundation, either version 3 of the License, or 80d11ac7eSGreg Roach * (at your option) any later version. 90d11ac7eSGreg Roach * This program is distributed in the hope that it will be useful, 100d11ac7eSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 110d11ac7eSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 120d11ac7eSGreg Roach * GNU General Public License for more details. 130d11ac7eSGreg Roach * You should have received a copy of the GNU General Public License 140d11ac7eSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 150d11ac7eSGreg Roach */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 180d11ac7eSGreg Roachnamespace Fisharebest\Webtrees\Services; 190d11ac7eSGreg Roach 200d11ac7eSGreg Roachuse Fisharebest\Webtrees\Database; 210d11ac7eSGreg Roachuse Fisharebest\Webtrees\DebugBar; 220d11ac7eSGreg Roachuse Fisharebest\Webtrees\Site; 238d0ebef0SGreg Roachuse Fisharebest\Webtrees\Webtrees; 240d11ac7eSGreg Roachuse GuzzleHttp\Client; 250d11ac7eSGreg Roachuse GuzzleHttp\Exception\RequestException; 260d11ac7eSGreg Roachuse Symfony\Component\HttpFoundation\Response; 270d11ac7eSGreg Roach 280d11ac7eSGreg Roach/** 290d11ac7eSGreg Roach * Automatic upgrades. 300d11ac7eSGreg Roach */ 310d11ac7eSGreg Roachclass UpgradeService 320d11ac7eSGreg Roach{ 330d11ac7eSGreg Roach // Regular expression to match a version string such as "1.7.10" or "2.0.0-alpha.1" 340d11ac7eSGreg Roach const REGEX_VERSION = '\d+\.\d+\.\d+(-[a-z0-9.-]+)?'; 350d11ac7eSGreg Roach 360d11ac7eSGreg Roach // Only check the webtrees server infrequently. 370d11ac7eSGreg Roach const CHECK_FOR_UPDATE_INTERVAL = 24 * 60 * 60; 380d11ac7eSGreg Roach 390d11ac7eSGreg Roach // Fetch information about upgrades from here. 400d11ac7eSGreg Roach // Note: earlier versions of webtrees used svn.webtrees.net, so we must maintain both URLs. 410d11ac7eSGreg Roach const UPDATE_URL = 'https://dev.webtrees.net/build/latest-version.txt'; 420d11ac7eSGreg Roach 430d11ac7eSGreg Roach // If the update server doesn't respond after this time, give up. 440d11ac7eSGreg Roach const HTTP_TIMEOUT = 3.0; 450d11ac7eSGreg Roach 460d11ac7eSGreg Roach /** 470d11ac7eSGreg Roach * @return bool 480d11ac7eSGreg Roach */ 490d11ac7eSGreg Roach public function isUpgradeAvailable(): bool 500d11ac7eSGreg Roach { 510d11ac7eSGreg Roach // If the latest version is unavailable, we will have an empty sting which equates to version 0. 520d11ac7eSGreg Roach 538d0ebef0SGreg Roach return version_compare(Webtrees::VERSION, $this->fetchLatestVersion()) < 0; 540d11ac7eSGreg Roach } 550d11ac7eSGreg Roach 560d11ac7eSGreg Roach /** 570d11ac7eSGreg Roach * What is the latest version of webtrees. 580d11ac7eSGreg Roach * 590d11ac7eSGreg Roach * @return string 600d11ac7eSGreg Roach */ 610d11ac7eSGreg Roach public function latestVersion(): string 620d11ac7eSGreg Roach { 630d11ac7eSGreg Roach $latest_version = $this->fetchLatestVersion(); 640d11ac7eSGreg Roach 65*65e02381SGreg Roach [$version] = explode('|', $latest_version); 660d11ac7eSGreg Roach 670d11ac7eSGreg Roach return $version; 680d11ac7eSGreg Roach } 690d11ac7eSGreg Roach 700d11ac7eSGreg Roach /** 710d11ac7eSGreg Roach * Where can we download the latest version of webtrees. 720d11ac7eSGreg Roach * 730d11ac7eSGreg Roach * @return string 740d11ac7eSGreg Roach */ 750d11ac7eSGreg Roach public function downloadUrl(): string 760d11ac7eSGreg Roach { 770d11ac7eSGreg Roach $latest_version = $this->fetchLatestVersion(); 780d11ac7eSGreg Roach 79*65e02381SGreg Roach [, , $url] = explode('|', $latest_version . '||'); 800d11ac7eSGreg Roach 810d11ac7eSGreg Roach return $url; 820d11ac7eSGreg Roach } 830d11ac7eSGreg Roach 840d11ac7eSGreg Roach /** 850d11ac7eSGreg Roach * Check with the webtrees.net server for the latest version of webtrees. 860d11ac7eSGreg Roach * Fetching the remote file can be slow, so check infrequently, and cache the result. 870d11ac7eSGreg Roach * Pass the current versions of webtrees, PHP and MySQL, as the response 880d11ac7eSGreg Roach * may be different for each. The server logs are used to generate 890d11ac7eSGreg Roach * installation statistics which can be found at http://dev.webtrees.net/statistics.html 900d11ac7eSGreg Roach * 910d11ac7eSGreg Roach * @return string 920d11ac7eSGreg Roach */ 930d11ac7eSGreg Roach private function fetchLatestVersion(): string 940d11ac7eSGreg Roach { 950d11ac7eSGreg Roach $last_update_timestamp = (int) Site::getPreference('LATEST_WT_VERSION_TIMESTAMP'); 960d11ac7eSGreg Roach 970d11ac7eSGreg Roach if ($last_update_timestamp < WT_TIMESTAMP - self::CHECK_FOR_UPDATE_INTERVAL) { 980d11ac7eSGreg Roach try { 990d11ac7eSGreg Roach $client = new Client([ 1000d11ac7eSGreg Roach 'timeout' => self::HTTP_TIMEOUT, 1010d11ac7eSGreg Roach ]); 1020d11ac7eSGreg Roach 1030d11ac7eSGreg Roach $response = $client->get(self::UPDATE_URL, [ 1040d11ac7eSGreg Roach 'query' => $this->serverParameters(), 1050d11ac7eSGreg Roach ]); 1060d11ac7eSGreg Roach 1070d11ac7eSGreg Roach if ($response->getStatusCode() === Response::HTTP_OK) { 1080d11ac7eSGreg Roach Site::setPreference('LATEST_WT_VERSION', $response->getBody()->getContents()); 109ebf05b8eSGreg Roach Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', (string) WT_TIMESTAMP); 1100d11ac7eSGreg Roach } 1110d11ac7eSGreg Roach } catch (RequestException $ex) { 1120d11ac7eSGreg Roach DebugBar::addThrowable($ex); 1130d11ac7eSGreg Roach } 1140d11ac7eSGreg Roach } 1150d11ac7eSGreg Roach 1160d11ac7eSGreg Roach return Site::getPreference('LATEST_WT_VERSION'); 1170d11ac7eSGreg Roach } 1180d11ac7eSGreg Roach 1190d11ac7eSGreg Roach /** 1200d11ac7eSGreg Roach * The upgrade server needs to know a little about this server. 1210d11ac7eSGreg Roach */ 1228f53f488SRico Sonntag private function serverParameters(): array 1230d11ac7eSGreg Roach { 1240d11ac7eSGreg Roach $mysql_version = Database::prepare("SHOW VARIABLES LIKE 'version'")->fetchOneRow(); 1250d11ac7eSGreg Roach 1260d11ac7eSGreg Roach $operating_system = DIRECTORY_SEPARATOR === '/' ? 'u' : 'w'; 1270d11ac7eSGreg Roach 1280d11ac7eSGreg Roach return [ 1298d0ebef0SGreg Roach 'w' => Webtrees::VERSION, 1300d11ac7eSGreg Roach 'p' => PHP_VERSION, 1310d11ac7eSGreg Roach 'm' => $mysql_version->value, 1320d11ac7eSGreg Roach 'o' => $operating_system, 1330d11ac7eSGreg Roach ]; 1340d11ac7eSGreg Roach } 1350d11ac7eSGreg Roach} 136