xref: /webtrees/app/Services/UpgradeService.php (revision e5a6b4d4f6f6e7ff2fba7ae2cf27546ae68a79cc)
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