Passed
Push — master ( a6447a...1efa54 )
by Roeland
24:37 queued 11:58
created

URLGenerator::getBaseUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 *
8
 * @author Arthur Schiwon <[email protected]>
9
 * @author Bart Visscher <[email protected]>
10
 * @author Christoph Wurst <[email protected]>
11
 * @author Felix Epp <[email protected]>
12
 * @author Joas Schilling <[email protected]>
13
 * @author Jörn Friedrich Dreyer <[email protected]>
14
 * @author Julius Haertl <[email protected]>
15
 * @author Julius Härtl <[email protected]>
16
 * @author Lukas Reschke <[email protected]>
17
 * @author mmccarn <[email protected]>
18
 * @author Morris Jobke <[email protected]>
19
 * @author Robin McCorkell <[email protected]>
20
 * @author Roeland Jago Douma <[email protected]>
21
 * @author Thomas Müller <[email protected]>
22
 * @author Thomas Tanghus <[email protected]>
23
 *
24
 * @license AGPL-3.0
25
 *
26
 * This code is free software: you can redistribute it and/or modify
27
 * it under the terms of the GNU Affero General Public License, version 3,
28
 * as published by the Free Software Foundation.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
 * GNU Affero General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU Affero General Public License, version 3,
36
 * along with this program. If not, see <http://www.gnu.org/licenses/>
37
 *
38
 */
39
40
namespace OC;
41
42
use OC\Route\Router;
43
use OCA\Theming\ThemingDefaults;
44
use OCP\ICacheFactory;
45
use OCP\IConfig;
46
use OCP\IRequest;
47
use OCP\IURLGenerator;
48
use RuntimeException;
49
50
/**
51
 * Class to generate URLs
52
 */
53
class URLGenerator implements IURLGenerator {
54
	/** @var IConfig */
55
	private $config;
56
	/** @var ICacheFactory */
57
	private $cacheFactory;
58
	/** @var IRequest */
59
	private $request;
60
	/** @var Router */
61
	private $router;
62
	/** @var null|string */
63
	private $baseUrl = null;
64
65
	public function __construct(IConfig $config,
66
								ICacheFactory $cacheFactory,
67
								IRequest $request,
68
								Router $router) {
69
		$this->config = $config;
70
		$this->cacheFactory = $cacheFactory;
71
		$this->request = $request;
72
		$this->router = $router;
73
	}
74
75
	/**
76
	 * Creates an url using a defined route
77
	 *
78
	 * @param string $routeName
79
	 * @param array $arguments args with param=>value, will be appended to the returned url
80
	 * @return string the url
81
	 *
82
	 * Returns a url to the given route.
83
	 */
84
	public function linkToRoute(string $routeName, array $arguments = []): string {
85
		return $this->router->generate($routeName, $arguments);
86
	}
87
88
	/**
89
	 * Creates an absolute url using a defined route
90
	 * @param string $routeName
91
	 * @param array $arguments args with param=>value, will be appended to the returned url
92
	 * @return string the url
93
	 *
94
	 * Returns an absolute url to the given route.
95
	 */
96
	public function linkToRouteAbsolute(string $routeName, array $arguments = []): string {
97
		return $this->getAbsoluteURL($this->linkToRoute($routeName, $arguments));
98
	}
99
100
	public function linkToOCSRouteAbsolute(string $routeName, array $arguments = []): string {
101
		$route = $this->router->generate('ocs.'.$routeName, $arguments, false);
102
103
		$indexPhpPos = strpos($route, '/index.php/');
104
		if ($indexPhpPos !== false) {
105
			$route = substr($route, $indexPhpPos + 10);
106
		}
107
108
		$route = substr($route, 7);
109
		$route = '/ocs/v2.php' . $route;
110
111
		return $this->getAbsoluteURL($route);
112
	}
113
114
	/**
115
	 * Creates an url
116
	 *
117
	 * @param string $appName app
118
	 * @param string $file file
119
	 * @param array $args array with param=>value, will be appended to the returned url
120
	 *    The value of $args will be urlencoded
121
	 * @return string the url
122
	 *
123
	 * Returns a url to the given app and file.
124
	 */
125
	public function linkTo(string $appName, string $file, array $args = []): string {
126
		$frontControllerActive = ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
127
128
		if ($appName !== '') {
129
			$app_path = \OC_App::getAppPath($appName);
130
			// Check if the app is in the app folder
131
			if ($app_path && file_exists($app_path . '/' . $file)) {
132
				if (substr($file, -3) === 'php') {
133
					$urlLinkTo = \OC::$WEBROOT . '/index.php/apps/' . $appName;
134
					if ($frontControllerActive) {
135
						$urlLinkTo = \OC::$WEBROOT . '/apps/' . $appName;
136
					}
137
					$urlLinkTo .= ($file !== 'index.php') ? '/' . $file : '';
138
				} else {
139
					$urlLinkTo = \OC_App::getAppWebPath($appName) . '/' . $file;
0 ignored issues
show
Bug introduced by
Are you sure OC_App::getAppWebPath($appName) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
					$urlLinkTo = /** @scrutinizer ignore-type */ \OC_App::getAppWebPath($appName) . '/' . $file;
Loading history...
140
				}
141
			} else {
142
				$urlLinkTo = \OC::$WEBROOT . '/' . $appName . '/' . $file;
143
			}
144
		} else {
145
			if (file_exists(\OC::$SERVERROOT . '/core/' . $file)) {
146
				$urlLinkTo = \OC::$WEBROOT . '/core/' . $file;
147
			} else {
148
				if ($frontControllerActive && $file === 'index.php') {
149
					$urlLinkTo = \OC::$WEBROOT . '/';
150
				} else {
151
					$urlLinkTo = \OC::$WEBROOT . '/' . $file;
152
				}
153
			}
154
		}
155
156
		if ($args && $query = http_build_query($args, '', '&')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $args of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
157
			$urlLinkTo .= '?' . $query;
158
		}
159
160
		return $urlLinkTo;
161
	}
162
163
	/**
164
	 * Creates path to an image
165
	 *
166
	 * @param string $appName app
167
	 * @param string $file image name
168
	 * @throws \RuntimeException If the image does not exist
169
	 * @return string the url
170
	 *
171
	 * Returns the path to the image.
172
	 */
173
	public function imagePath(string $appName, string $file): string {
174
		$cache = $this->cacheFactory->createDistributed('imagePath-'.md5($this->getBaseUrl()).'-');
175
		$cacheKey = $appName.'-'.$file;
176
		if ($key = $cache->get($cacheKey)) {
177
			return $key;
178
		}
179
180
		// Read the selected theme from the config file
181
		$theme = \OC_Util::getTheme();
182
183
		//if a theme has a png but not an svg always use the png
184
		$basename = substr(basename($file),0,-4);
185
186
		$appPath = \OC_App::getAppPath($appName);
187
188
		// Check if the app is in the app folder
189
		$path = '';
190
		$themingEnabled = $this->config->getSystemValue('installed', false) && \OCP\App::isEnabled('theming') && \OC_App::isAppLoaded('theming');
191
		$themingImagePath = false;
192
		if ($themingEnabled) {
193
			$themingDefaults = \OC::$server->getThemingDefaults();
194
			if ($themingDefaults instanceof ThemingDefaults) {
0 ignored issues
show
introduced by
$themingDefaults is always a sub-type of OCA\Theming\ThemingDefaults.
Loading history...
195
				$themingImagePath = $themingDefaults->replaceImagePath($appName, $file);
196
			}
197
		}
198
199
		if (file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$file")) {
200
			$path = \OC::$WEBROOT . "/themes/$theme/apps/$appName/img/$file";
201
		} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$basename.svg")
202
			&& file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$basename.png")) {
203
			$path = \OC::$WEBROOT . "/themes/$theme/apps/$appName/img/$basename.png";
204
		} elseif (!empty($appName) and file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$file")) {
205
			$path = \OC::$WEBROOT . "/themes/$theme/$appName/img/$file";
206
		} elseif (!empty($appName) and (!file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$basename.svg")
207
			&& file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$basename.png"))) {
208
			$path = \OC::$WEBROOT . "/themes/$theme/$appName/img/$basename.png";
209
		} elseif (file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$file")) {
210
			$path = \OC::$WEBROOT . "/themes/$theme/core/img/$file";
211
		} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.svg")
212
			&& file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.png")) {
213
			$path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
214
		} elseif ($themingEnabled && $themingImagePath) {
215
			$path = $themingImagePath;
216
		} elseif ($appPath && file_exists($appPath . "/img/$file")) {
217
			$path = \OC_App::getAppWebPath($appName) . "/img/$file";
0 ignored issues
show
Bug introduced by
Are you sure OC_App::getAppWebPath($appName) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
			$path = /** @scrutinizer ignore-type */ \OC_App::getAppWebPath($appName) . "/img/$file";
Loading history...
218
		} elseif ($appPath && !file_exists($appPath . "/img/$basename.svg")
219
			&& file_exists($appPath . "/img/$basename.png")) {
220
			$path = \OC_App::getAppWebPath($appName) . "/img/$basename.png";
221
		} elseif (!empty($appName) and file_exists(\OC::$SERVERROOT . "/$appName/img/$file")) {
222
			$path = \OC::$WEBROOT . "/$appName/img/$file";
223
		} elseif (!empty($appName) and (!file_exists(\OC::$SERVERROOT . "/$appName/img/$basename.svg")
224
				&& file_exists(\OC::$SERVERROOT . "/$appName/img/$basename.png"))) {
225
			$path = \OC::$WEBROOT . "/$appName/img/$basename.png";
226
		} elseif (file_exists(\OC::$SERVERROOT . "/core/img/$file")) {
227
			$path = \OC::$WEBROOT . "/core/img/$file";
228
		} elseif (!file_exists(\OC::$SERVERROOT . "/core/img/$basename.svg")
229
			&& file_exists(\OC::$SERVERROOT . "/core/img/$basename.png")) {
230
			$path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
231
		}
232
233
		if ($path !== '') {
234
			$cache->set($cacheKey, $path);
235
			return $path;
236
		}
237
238
		throw new RuntimeException('image not found: image:' . $file . ' webroot:' . \OC::$WEBROOT . ' serverroot:' . \OC::$SERVERROOT);
239
	}
240
241
242
	/**
243
	 * Makes an URL absolute
244
	 * @param string $url the url in the ownCloud host
245
	 * @return string the absolute version of the url
246
	 */
247
	public function getAbsoluteURL(string $url): string {
248
		$separator = strpos($url, '/') === 0 ? '' : '/';
249
250
		if (\OC::$CLI && !\defined('PHPUNIT_RUN')) {
251
			return rtrim($this->config->getSystemValue('overwrite.cli.url'), '/') . '/' . ltrim($url, '/');
252
		}
253
		// The ownCloud web root can already be prepended.
254
		if (\OC::$WEBROOT !== '' && strpos($url, \OC::$WEBROOT) === 0) {
255
			$url = substr($url, \strlen(\OC::$WEBROOT));
256
		}
257
258
		return $this->getBaseUrl() . $separator . $url;
259
	}
260
261
	/**
262
	 * @param string $key
263
	 * @return string url to the online documentation
264
	 */
265
	public function linkToDocs(string $key): string {
266
		$theme = \OC::$server->getThemingDefaults();
267
		return $theme->buildDocLinkToKey($key);
268
	}
269
270
	/**
271
	 * @return string base url of the current request
272
	 */
273
	public function getBaseUrl(): string {
274
		if ($this->baseUrl === null) {
275
			$this->baseUrl = $this->request->getServerProtocol() . '://' . $this->request->getServerHost() . \OC::$WEBROOT;
276
		}
277
		return $this->baseUrl;
278
	}
279
}
280