Completed
Pull Request — master (#463)
by
unknown
35:46
created

Fetcher   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 0%

Importance

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

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getBaseDownloadPath() 0 4 1
A getMd5() 0 6 1
A getOwncloud() 0 20 3
A __construct() 0 5 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
	public function __construct(Client $httpClient, Locator $locator, ConfigReader $configReader){
63
		$this->httpClient = $httpClient;
64
		$this->locator = $locator;
65
		$this->configReader = $configReader;
66
	}
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(
0 ignored issues
show
Bug introduced by
The method createRequest() does not exist on GuzzleHttp\Client. Did you maybe mean request()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
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);
0 ignored issues
show
Documentation introduced by
$response is of type object<Psr\Http\Message\ResponseInterface>, but the function expects a object<GuzzleHttp\Message\ResponseInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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
	public function getFeed(){
123
		$url = $this->getFeedUrl();
124
		$xml = $this->download($url);
125
		$tmp = [];
126
		if ($xml){
127
			$loadEntities = libxml_disable_entity_loader(true);
128
			$data = @simplexml_load_string($xml);
129
			libxml_disable_entity_loader($loadEntities);
130
			if ($data !== false){
131
				$tmp['version'] = (string) $data->version;
132
				$tmp['versionstring'] = (string) $data->versionstring;
133
				$tmp['url'] = (string) $data->url;
134
				$tmp['web'] = (string) $data->web;
135
			}
136
		}
137
138
		return new Feed($tmp);
139
	}
140
141
	/**
142
	 * @return mixed|string
143
	 */
144
	public function getUpdateChannel(){
145
		$channel = $this->configReader->getByPath('apps.core.OC_Channel');
146
		if (is_null($channel)) {
147
			return $this->locator->getChannelFromVersionsFile();
148
		}
149
150
		return $channel;
151
	}
152
153
	/**
154
	 * Produce complete feed URL
155
	 * @return string
156
	 */
157
	protected function getFeedUrl(){
158
		$currentVersion = $this->configReader->getByPath('system.version');
159
		$version = explode('.', $currentVersion);
160
		$version['installed'] = $this->configReader->getByPath('apps.core.installedat');
161
		$version['updated'] = $this->configReader->getByPath('apps.core.lastupdatedat');
162
		$version['updatechannel'] = $this->getUpdateChannel();
163
		$version['edition'] = $this->configReader->getEdition();
164
		$version['build'] = $this->locator->getBuild();
165
166
		// Read updater server URL from config
167
		$updaterServerUrl = $this->configReader->get(['system', 'updater.server.url']);
168
		if ((bool) $updaterServerUrl === false){
169
			$updaterServerUrl = self::DEFAULT_BASE_URL;
170
		}
171
172
		$url = $updaterServerUrl . '?version=' . implode('x', $version);
173
		return $url;
174
	}
175
176
	/**
177
	 * Get URL content
178
	 * @param string $url
179
	 * @return string
180
	 * @throws \UnexpectedValueException
181
	 */
182
	protected function download($url){
183
		$response = $this->httpClient->get($url, ['timeout' => 600]);
184
		$this->validateResponse($response);
0 ignored issues
show
Documentation introduced by
$response is of type object<Psr\Http\Message\ResponseInterface>, but the function expects a object<GuzzleHttp\Message\ResponseInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
185
		return $response->getBody()->getContents();
186
	}
187
188
	/**
189
	 * Check if request was successful
190
	 * @param \GuzzleHttp\Message\ResponseInterface $response
191
	 * @throws \UnexpectedValueException
192
	 */
193
	protected function validateResponse($response){
194
		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
	}
203
204
}
205