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