File: UpdateCheck.php

package info (click to toggle)
matomo 5.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 95,068 kB
  • sloc: php: 289,425; xml: 127,249; javascript: 112,130; python: 202; sh: 178; makefile: 20; sql: 10
file content (128 lines) | stat: -rw-r--r-- 4,153 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik;

use Piwik\Container\StaticContainer;

/**
 * Class to check if a newer version of Piwik is available
 */
class UpdateCheck
{
    public const CHECK_INTERVAL = 28800; // every 8 hours
    public const UI_CLICK_CHECK_INTERVAL = 10; // every 10s when user clicks UI link
    public const LAST_CHECK_FAILED = 'UpdateCheck_LastCheckFailed';
    public const LAST_TIME_CHECKED = 'UpdateCheck_LastTimeChecked';
    public const LATEST_VERSION = 'UpdateCheck_LatestVersion';
    public const SOCKET_TIMEOUT = 5;

    /**
     * Check for a newer version
     *
     * @param bool $force Force check
     * @param int $interval Interval used for update checks
     */
    public static function check($force = false, $interval = null)
    {
        if (!SettingsPiwik::isAutoUpdateEnabled()) {
            return;
        }

        if ($interval === null) {
            $interval = self::CHECK_INTERVAL;
        }

        $lastTimeChecked = Option::get(self::LAST_TIME_CHECKED);
        if (
            $force
            || $lastTimeChecked === false
            || time() - $interval > $lastTimeChecked
        ) {
            // set the time checked first, so that parallel Piwik requests don't all trigger the http requests
            Option::set(self::LAST_TIME_CHECKED, time(), $autoLoad = 1);

            $latestVersion = self::getLatestAvailableVersionNumber();
            $latestVersion = trim((string) $latestVersion);
            if (!preg_match('~^[0-9][0-9a-zA-Z_.-]*$~D', $latestVersion)) {
                $latestVersion = '';
            }

            $hasLastCheckFailed = '' === $latestVersion;

            Option::set(self::LAST_CHECK_FAILED, $hasLastCheckFailed);

            if ($hasLastCheckFailed) {
                // retry check on next request if previous attempt failed
                Option::set(self::LAST_TIME_CHECKED, $lastTimeChecked, $autoLoad = 1);
            } else {
                Option::set(self::LATEST_VERSION, $latestVersion);
            }
        }
    }

    /**
     * Get the latest available version number for the currently active release channel. Eg '2.15.0-b4' or '2.15.0'.
     * Should return a semantic version number in format MAJOR.MINOR.PATCH (https://semver.org/).
     * Returns an empty string in case one cannot connect to the remote server.
     * @return string
     */
    private static function getLatestAvailableVersionNumber()
    {
        $releaseChannels = StaticContainer::get('\Piwik\Plugin\ReleaseChannels');
        $channel = $releaseChannels->getActiveReleaseChannel();
        $url = $channel->getUrlToCheckForLatestAvailableVersion();

        try {
            $latestVersion = Http::sendHttpRequest($url, self::SOCKET_TIMEOUT);
        } catch (\Exception $e) {
            // e.g., disable_functions = fsockopen; allow_url_open = Off
            $latestVersion = '';
        }

        return $latestVersion;
    }

    /**
     * Returns the latest available version number. Does not perform a check whether a later version is available.
     *
     * @return false|string
     */
    public static function getLatestVersion()
    {
        return Option::get(self::LATEST_VERSION);
    }

    /**
     * Returns whether the last update check was flagged as having failed or not.
     *
     */
    public static function hasLastCheckFailed(): bool
    {
        return (bool) Option::get(self::LAST_CHECK_FAILED);
    }

    /**
     * Returns version number of a newer Piwik release.
     *
     * @return string|bool  false if current version is the latest available,
     *                       or the latest version number if a newest release is available
     */
    public static function isNewestVersionAvailable()
    {
        $latestVersion = self::getLatestVersion();
        if (
            !empty($latestVersion)
            && version_compare(Version::VERSION, $latestVersion) == -1
        ) {
            return $latestVersion;
        }
        return false;
    }
}