xref: /webtrees/app/Services/UpgradeService.php (revision bf57b58092d898900e7b5483b92b51c65a15460e)
10d11ac7eSGreg Roach<?php
20d11ac7eSGreg Roach/**
30d11ac7eSGreg Roach * webtrees: online genealogy
48fcd0d32SGreg Roach * Copyright (C) 2019 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
20*bf57b580SGreg Roachuse Carbon\Carbon;
210d11ac7eSGreg Roachuse Fisharebest\Webtrees\Site;
228d0ebef0SGreg Roachuse Fisharebest\Webtrees\Webtrees;
230d11ac7eSGreg Roachuse GuzzleHttp\Client;
240d11ac7eSGreg Roachuse GuzzleHttp\Exception\RequestException;
250d11ac7eSGreg Roachuse Symfony\Component\HttpFoundation\Response;
260d11ac7eSGreg Roach
270d11ac7eSGreg Roach/**
280d11ac7eSGreg Roach * Automatic upgrades.
290d11ac7eSGreg Roach */
300d11ac7eSGreg Roachclass UpgradeService
310d11ac7eSGreg Roach{
320d11ac7eSGreg Roach    // Only check the webtrees server infrequently.
3316d6367aSGreg Roach    private const CHECK_FOR_UPDATE_INTERVAL = 24 * 60 * 60;
340d11ac7eSGreg Roach
350d11ac7eSGreg Roach    // Fetch information about upgrades from here.
360d11ac7eSGreg Roach    // Note: earlier versions of webtrees used svn.webtrees.net, so we must maintain both URLs.
3716d6367aSGreg Roach    private const UPDATE_URL = 'https://dev.webtrees.net/build/latest-version.txt';
380d11ac7eSGreg Roach
390d11ac7eSGreg Roach    // If the update server doesn't respond after this time, give up.
4016d6367aSGreg Roach    private const HTTP_TIMEOUT = 3.0;
410d11ac7eSGreg Roach
420d11ac7eSGreg Roach    /**
430d11ac7eSGreg Roach     * @return bool
440d11ac7eSGreg Roach     */
450d11ac7eSGreg Roach    public function isUpgradeAvailable(): bool
460d11ac7eSGreg Roach    {
470d11ac7eSGreg Roach        // If the latest version is unavailable, we will have an empty sting which equates to version 0.
480d11ac7eSGreg Roach
498d0ebef0SGreg Roach        return version_compare(Webtrees::VERSION, $this->fetchLatestVersion()) < 0;
500d11ac7eSGreg Roach    }
510d11ac7eSGreg Roach
520d11ac7eSGreg Roach    /**
530d11ac7eSGreg Roach     * What is the latest version of webtrees.
540d11ac7eSGreg Roach     *
550d11ac7eSGreg Roach     * @return string
560d11ac7eSGreg Roach     */
570d11ac7eSGreg Roach    public function latestVersion(): string
580d11ac7eSGreg Roach    {
590d11ac7eSGreg Roach        $latest_version = $this->fetchLatestVersion();
600d11ac7eSGreg Roach
6165e02381SGreg Roach        [$version] = explode('|', $latest_version);
620d11ac7eSGreg Roach
630d11ac7eSGreg Roach        return $version;
640d11ac7eSGreg Roach    }
650d11ac7eSGreg Roach
660d11ac7eSGreg Roach    /**
670d11ac7eSGreg Roach     * Where can we download the latest version of webtrees.
680d11ac7eSGreg Roach     *
690d11ac7eSGreg Roach     * @return string
700d11ac7eSGreg Roach     */
710d11ac7eSGreg Roach    public function downloadUrl(): string
720d11ac7eSGreg Roach    {
730d11ac7eSGreg Roach        $latest_version = $this->fetchLatestVersion();
740d11ac7eSGreg Roach
7565e02381SGreg Roach        [, , $url] = explode('|', $latest_version . '||');
760d11ac7eSGreg Roach
770d11ac7eSGreg Roach        return $url;
780d11ac7eSGreg Roach    }
790d11ac7eSGreg Roach
800d11ac7eSGreg Roach    /**
810d11ac7eSGreg Roach     * Check with the webtrees.net server for the latest version of webtrees.
820d11ac7eSGreg Roach     * Fetching the remote file can be slow, so check infrequently, and cache the result.
830d11ac7eSGreg Roach     * Pass the current versions of webtrees, PHP and MySQL, as the response
840d11ac7eSGreg Roach     * may be different for each. The server logs are used to generate
850d11ac7eSGreg Roach     * installation statistics which can be found at http://dev.webtrees.net/statistics.html
860d11ac7eSGreg Roach     *
870d11ac7eSGreg Roach     * @return string
880d11ac7eSGreg Roach     */
890d11ac7eSGreg Roach    private function fetchLatestVersion(): string
900d11ac7eSGreg Roach    {
910d11ac7eSGreg Roach        $last_update_timestamp = (int) Site::getPreference('LATEST_WT_VERSION_TIMESTAMP');
920d11ac7eSGreg Roach
93*bf57b580SGreg Roach        $current_timestamp = Carbon::now()->timestamp;
94*bf57b580SGreg Roach
95*bf57b580SGreg Roach        if ($last_update_timestamp < $current_timestamp - self::CHECK_FOR_UPDATE_INTERVAL) {
960d11ac7eSGreg Roach            try {
970d11ac7eSGreg Roach                $client = new Client([
980d11ac7eSGreg Roach                    'timeout' => self::HTTP_TIMEOUT,
990d11ac7eSGreg Roach                ]);
1000d11ac7eSGreg Roach
1010d11ac7eSGreg Roach                $response = $client->get(self::UPDATE_URL, [
1020d11ac7eSGreg Roach                    'query' => $this->serverParameters(),
1030d11ac7eSGreg Roach                ]);
1040d11ac7eSGreg Roach
1050d11ac7eSGreg Roach                if ($response->getStatusCode() === Response::HTTP_OK) {
1060d11ac7eSGreg Roach                    Site::setPreference('LATEST_WT_VERSION', $response->getBody()->getContents());
107*bf57b580SGreg Roach                    Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', (string) $current_timestamp);
1080d11ac7eSGreg Roach                }
1090d11ac7eSGreg Roach            } catch (RequestException $ex) {
110c6a0ce5cSGreg Roach                // Can't connect to the server?
111c6a0ce5cSGreg Roach                // Use the existing information about latest versions.
1120d11ac7eSGreg Roach            }
1130d11ac7eSGreg Roach        }
1140d11ac7eSGreg Roach
1150d11ac7eSGreg Roach        return Site::getPreference('LATEST_WT_VERSION');
1160d11ac7eSGreg Roach    }
1170d11ac7eSGreg Roach
1180d11ac7eSGreg Roach    /**
1190d11ac7eSGreg Roach     * The upgrade server needs to know a little about this server.
1200d11ac7eSGreg Roach     */
1218f53f488SRico Sonntag    private function serverParameters(): array
1220d11ac7eSGreg Roach    {
1230d11ac7eSGreg Roach        $operating_system = DIRECTORY_SEPARATOR === '/' ? 'u' : 'w';
1240d11ac7eSGreg Roach
1250d11ac7eSGreg Roach        return [
1268d0ebef0SGreg Roach            'w' => Webtrees::VERSION,
1270d11ac7eSGreg Roach            'p' => PHP_VERSION,
1280d11ac7eSGreg Roach            'o' => $operating_system,
1290d11ac7eSGreg Roach        ];
1300d11ac7eSGreg Roach    }
1310d11ac7eSGreg Roach}
132