Fetcher   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 61.43%

Importance

Changes 0
Metric Value
wmc 16
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 174
ccs 43
cts 70
cp 0.6143
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getOwncloud() 0 20 3
A getBaseDownloadPath() 0 4 1
A getMd5() 0 6 1
A getFeed() 0 18 3
A getUpdateChannel() 0 8 2
A getFeedUrl() 0 18 2
A download() 0 5 1
A validateResponse() 0 10 2
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use GuzzleHttp\Client;
25
26
/**
27
 * Class Fetcher
28
 *
29
 * @package Owncloud\Updater\Utils
30
 */
31
class Fetcher {
32
33
	const DEFAULT_BASE_URL = 'https://updates.owncloud.com/server/';
34
35
	/**
36
	 * @var Locator $locator
37
	 */
38
	protected $locator;
39
40
	/**
41
	 * @var ConfigReader $configReader
42
	 */
43
	protected $configReader;
44
45
	/**
46
	 * @var Client $httpClient
47
	 */
48
	protected $httpClient;
49
	protected $requiredFeedEntries = [
50
		'version',
51
		'versionstring',
52
		'url'
53
	];
54
55
	/**
56
	 * Constructor
57
	 *
58
	 * @param Client $httpClient
59
	 * @param Locator $locator
60
	 * @param ConfigReader $configReader
61
	 */
62 3
	public function __construct(Client $httpClient, Locator $locator, ConfigReader $configReader){
63 3
		$this->httpClient = $httpClient;
64 3
		$this->locator = $locator;
65 3
		$this->configReader = $configReader;
66 3
	}
67
68
	/**
69
	 * Download new ownCloud package
70
	 * @param Feed $feed
71
	 * @param Callable $onProgress
72
	 * @throws \Exception
73
	 * @throws \UnexpectedValueException
74
	 */
75
	public function getOwncloud(Feed $feed, callable $onProgress){
76
		if ($feed->isValid()){
77
			$downloadPath = $this->getBaseDownloadPath($feed);
78
			if (!is_writable(dirname($downloadPath))){
79
				throw new \Exception(dirname($downloadPath) . ' is not writable.');
80
			}
81
			$url = $feed->getUrl();
82
			$request = $this->httpClient->createRequest(
83
					'GET',
84
					$url,
85
					[
86
						'save_to' => $downloadPath,
87
						'timeout' => 600
88
					]
89
			);
90
			$request->getEmitter()->on('progress', $onProgress);
91
			$response = $this->httpClient->send($request);
92
			$this->validateResponse($response);
93
		}
94
	}
95
96
	/**
97
	 * Produce a local path to save the package to
98
	 * @param Feed $feed
99
	 * @return string
100
	 */
101
	public function getBaseDownloadPath(Feed $feed){
102
		$basePath = $this->locator->getDownloadBaseDir();
103
		return $basePath . '/' . $feed->getDownloadedFileName();
104
	}
105
106
	/**
107
	 * Get md5 sum for the package
108
	 * @param Feed $feed
109
	 * @return string
110
	 */
111
	public function getMd5(Feed $feed){
112
		$fullChecksum = $this->download($feed->getChecksumUrl());
113
		// we got smth like "5776cbd0a95637ade4b2c0d8694d8fca  -"
114
		//strip trailing space & dash
115
		return substr($fullChecksum, 0, 32);
116
	}
117
118
	/**
119
	 * Read update feed for new releases
120
	 * @return Feed
121
	 */
122 3
	public function getFeed(){
123 3
		$url = $this->getFeedUrl();
124 3
		$xml = $this->download($url);
125 3
		$tmp = [];
126 3
		if ($xml){
127 2
			$loadEntities = libxml_disable_entity_loader(true);
128 2
			$data = @simplexml_load_string($xml);
129 2
			libxml_disable_entity_loader($loadEntities);
130 2
			if ($data !== false){
131 1
				$tmp['version'] = (string) $data->version;
132 1
				$tmp['versionstring'] = (string) $data->versionstring;
133 1
				$tmp['url'] = (string) $data->url;
134 1
				$tmp['web'] = (string) $data->web;
135
			}
136
		}
137
138 3
		return new Feed($tmp);
139
	}
140
141
	/**
142
	 * @return mixed|string
143
	 */
144 3
	public function getUpdateChannel(){
145 3
		$channel = $this->configReader->getByPath('apps.core.OC_Channel');
146 3
		if (is_null($channel)) {
147
			return $this->locator->getChannelFromVersionsFile();
148
		}
149
150 3
		return $channel;
151
	}
152
153
	/**
154
	 * Produce complete feed URL
155
	 * @return string
156
	 */
157 3
	protected function getFeedUrl(){
158 3
		$currentVersion = $this->configReader->getByPath('system.version');
159 3
		$version = explode('.', $currentVersion);
160 3
		$version['installed'] = $this->configReader->getByPath('apps.core.installedat');
161 3
		$version['updated'] = $this->configReader->getByPath('apps.core.lastupdatedat');
162 3
		$version['updatechannel'] = $this->getUpdateChannel();
163 3
		$version['edition'] = $this->configReader->getEdition();
164 3
		$version['build'] = $this->locator->getBuild();
165
166
		// Read updater server URL from config
167 3
		$updaterServerUrl = $this->configReader->get(['system', 'updater.server.url']);
168 3
		if ((bool) $updaterServerUrl === false){
169 3
			$updaterServerUrl = self::DEFAULT_BASE_URL;
170
		}
171
172 3
		$url = $updaterServerUrl . '?version=' . implode('x', $version);
173 3
		return $url;
174
	}
175
176
	/**
177
	 * Get URL content
178
	 * @param string $url
179
	 * @return string
180
	 * @throws \UnexpectedValueException
181
	 */
182 3
	protected function download($url){
183 3
		$response = $this->httpClient->get($url, ['timeout' => 600]);
184 3
		$this->validateResponse($response);
185 3
		return $response->getBody()->getContents();
186
	}
187
188
	/**
189
	 * Check if request was successful
190
	 * @param \GuzzleHttp\Message\ResponseInterface $response
191
	 * @throws \UnexpectedValueException
192
	 */
193 3
	protected function validateResponse($response){
194 3
		if ($response->getStatusCode() !== 200){
195
			throw new \UnexpectedValueException(
196
					'Failed to download '
197
					. $response->getEffectiveUrl()
198
					. '. Server responded with '
199
					. $response->getStatusCode()
200
					. ' instead of 200.');
201
		}
202 3
	}
203
204
}
205