Completed
Push — 16.1 ( 263fa0...62d2b3 )
by Ralf
33:50 queued 17:47
created

Updates::available()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 1
nop 1
dl 0
loc 27
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * EGroupware API - Check for updates
4
 *
5
 * @link http://www.egroupware.org
6
 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
7
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
8
 * @package api
9
 * @subpackage framework
10
 * @access public
11
 */
12
13
namespace EGroupware\Api\Framework;
14
15
use EGroupware\Api\Html;
16
use EGroupware\Api\Cache;
17
use EGroupware\Api;
18
19
/**
20
 * Check for updates
21
 *
22
 * https://www.egroupware.org/currentversion
23
 *
24
 * Contains multiple lines with version numbers:
25
 * 1. current stable version      eg. 17.1.20180118
26
 * 2. last stable security update eg. 17.1.20180118
27
 * 3. last old-stable security up.eg. 16.1.20171106 (only if that is still secure!)
28
 * 4. further old secure versions, if available
29
 */
30
class Updates
31
{
32
	/**
33
	 * URL to check for security or maintenance updates
34
	 */
35
	const CURRENT_VERSION_URL = 'https://www.egroupware.org/currentversion';
36
	/**
37
	 * How long to cache (in secs) / often to check for updates
38
	 */
39
	const VERSIONS_CACHE_TIMEOUT = 7200;
40
	/**
41
	 * After how many days of not applied security updates, start warning non-admins too
42
	 */
43
	const WARN_USERS_DAYS = 5;
44
45
	/**
46
	 * Get versions of available updates
47
	 *
48
	 * @param string $api =null major api version to return security for, default latest
49
	 * @return array verions for keys "current" and "security"
50
	 */
51
	public static function available($api=null)
52
	{
53
		$versions = Cache::getTree(__CLASS__, 'versions', function() use ($api)
54
		{
55
			$versions = array();
56
			$security = null;
57
			if (($remote = file_get_contents(self::CURRENT_VERSION_URL, false, Api\Framework::proxy_context())))
58
			{
59
				$all_versions = explode("\n", $remote);
60
				$current = array_shift($all_versions);
61
				if (empty($all_versions)) $all_versions = array($current);
62
				// find latest security release for optional API version
63
				foreach(array_reverse($all_versions) as $security)
64
				{
65
					if (isset($api) && $api === substr($security, 0, strlen($api))) break;
66
				}
67
				$versions = array(
68
					'current'  => $current,		// last maintenance update
69
					'security' => $security,	// last security update
70
				);
71
			}
72
			return $versions;
73
		}, array(), self::VERSIONS_CACHE_TIMEOUT);
74
75
		//error_log(__METHOD__."($api) returning ".array2string($versions));
76
		return $versions;
77
	}
78
79
	/**
80
	 * Check update status
81
	 *
82
	 * @return string
83
	 * @todo Check from client-side, if server-side check fails
84
	 */
85
	public static function notification()
86
	{
87
		$api = self::api_version();
88
		$api_major = $matches = null;
89
		if (preg_match('/^(\d+\.\d+)\./', $api, $matches))
90
		{
91
			$api_major = $matches[1];
92
		}
93
94
		$versions = self::available($api_major);
95
96
		if ($versions)
97
		{
98
			if (version_compare($api, $versions['security'], '<'))
99
			{
100
				if (!$GLOBALS['egw_info']['user']['apps']['admin'] && !self::update_older($versions['security'], self::WARN_USERS_DAYS))
101
				{
102
					return null;
103
				}
104
				return Html::a_href(Html::image('api', 'security-update', lang('EGroupware security update %1 needs to be installed!', $versions['security'])),
105
					'http://www.egroupware.org/changelog', null, ' target="_blank"');
106
			}
107
			if ($GLOBALS['egw_info']['user']['apps']['admin'] && version_compare($api, $versions['current'], '<'))
108
			{
109
				$msg = substr($versions['current'], 0, strlen($api_major)) == $api_major ?
110
					lang('EGroupware maintenance update %1 available', $versions['current']) :
111
					lang('New EGroupware release %1 available', $versions['current']);
112
				return Html::a_href(Html::image('api', 'update', $msg),
113
					'http://www.egroupware.org/changelog', null, ' target="_blank"');
114
			}
115
		}
116
		elseif ($GLOBALS['egw_info']['user']['apps']['admin'])
117
		{
118
			$error = lang('Automatic update check failed, you need to check manually!');
119
			if (!ini_get('allow_url_fopen'))
120
			{
121
				$error .= "\n".lang('%1 setting "%2" = %3 disallows access via http!',
122
					'php.ini', 'allow_url_fopen', array2string(ini_get('allow_url_fopen')));
123
			}
124
			return Html::a_href(Html::image('api', 'update', $error),
125
				'http://www.egroupware.org/changelog', null, ' target="_blank" data-api-version="'.$api.'"');
126
		}
127
		return null;
128
	}
129
130
	/**
131
	 * Check if version is older then $days days
132
	 *
133
	 * @param string $version eg. "14.1.20140715" last part is checked (only if > 20140000!)
134
	 * @param int $days
135
	 * @return boolean
136
	 */
137
	protected static function update_older($version, $days)
138
	{
139
		list(,,$date) = explode('.', $version);
140
		if ($date < 20140000) return false;
141
		$version_timestamp = mktime(0, 0, 0, (int)substr($date, 4, 2), (int)substr($date, -2), (int)substr($date, 0, 4));
142
143
		return (time() - $version_timestamp) / 86400 > $days;
144
	}
145
146
	/**
147
	 * Get current API version from api/setup/setup.inc.php "maintenance_release" or database, whichever is bigger
148
	 *
149
	 * @param string &$changelog on return path to changelog
150
	 * @return string
151
	 */
152
	public static function api_version(&$changelog=null)
153
	{
154
		$changelog = EGW_SERVER_ROOT.'/doc/rpm-build/debian.changes';
155
156
		return Cache::getTree(__CLASS__, 'api_version', function()
157
		{
158
			$version = preg_replace('/[^0-9.]/', '', $GLOBALS['egw_info']['server']['versions']['api']);
159
160
			if (empty($GLOBALS['egw_info']['server']['versions']['maintenance_release']))
161
			{
162
				$setup_info = null;
163
				include (EGW_SERVER_ROOT.'/api/setup/setup.inc.php');
164
				$GLOBALS['egw_info']['server']['versions'] += $setup_info['api']['versions'];
165
				unset($setup_info);
166
			}
167
			if (version_compare($version, $GLOBALS['egw_info']['server']['versions']['maintenance_release'], '<'))
168
			{
169
				$version = $GLOBALS['egw_info']['server']['versions']['maintenance_release'];
170
			}
171
			return $version;
172
		}, array(), 300);
173
	}
174
}
175