Completed
Push — master ( 34c0b9...0c1cf5 )
by Lukas
08:37
created

OC_Util::checkServer()   F

Complexity

Conditions 45
Paths > 20000

Size

Total Lines 246
Code Lines 144

Duplication

Lines 15
Ratio 6.1 %

Importance

Changes 0
Metric Value
cc 45
eloc 144
nc 875522
nop 1
dl 15
loc 246
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author Adam Williamson <[email protected]>
4
 * @author Andreas Fischer <[email protected]>
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bart Visscher <[email protected]>
7
 * @author Bernhard Posselt <[email protected]>
8
 * @author Birk Borkason <[email protected]>
9
 * @author Björn Schießle <[email protected]>
10
 * @author Brice Maron <[email protected]>
11
 * @author Christoph Wurst <[email protected]>
12
 * @author Christopher Schäpers <[email protected]>
13
 * @author Clark Tomlinson <[email protected]>
14
 * @author cmeh <[email protected]>
15
 * @author Florin Peter <[email protected]>
16
 * @author Frank Karlitschek <[email protected]>
17
 * @author Georg Ehrke <[email protected]>
18
 * @author helix84 <[email protected]>
19
 * @author Individual IT Services <[email protected]>
20
 * @author Jakob Sack <[email protected]>
21
 * @author Joas Schilling <[email protected]>
22
 * @author Jörn Friedrich Dreyer <[email protected]>
23
 * @author Lukas Reschke <[email protected]>
24
 * @author Markus Goetz <[email protected]>
25
 * @author Martin Mattel <[email protected]>
26
 * @author Marvin Thomas Rabe <[email protected]>
27
 * @author Michael Gapczynski <[email protected]>
28
 * @author Morris Jobke <[email protected]>
29
 * @author Robin Appelman <[email protected]>
30
 * @author Robin McCorkell <[email protected]>
31
 * @author Roeland Jago Douma <[email protected]>
32
 * @author Stefan Rado <[email protected]>
33
 * @author Stefan Weil <[email protected]>
34
 * @author Thomas Müller <[email protected]>
35
 * @author Thomas Tanghus <[email protected]>
36
 * @author Victor Dubiniuk <[email protected]>
37
 * @author Vincent Petry <[email protected]>
38
 * @author Volkan Gezer <[email protected]>
39
 *
40
 * @copyright Copyright (c) 2016, ownCloud, Inc.
41
 * @license AGPL-3.0
42
 *
43
 * This code is free software: you can redistribute it and/or modify
44
 * it under the terms of the GNU Affero General Public License, version 3,
45
 * as published by the Free Software Foundation.
46
 *
47
 * This program is distributed in the hope that it will be useful,
48
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
49
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50
 * GNU Affero General Public License for more details.
51
 *
52
 * You should have received a copy of the GNU Affero General Public License, version 3,
53
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
54
 *
55
 */
56
57
use OCP\IConfig;
58
use OCP\IGroupManager;
59
use OCP\IUser;
60
61
class OC_Util {
62
	public static $scripts = array();
63
	public static $styles = array();
64
	public static $headers = array();
65
	private static $rootMounted = false;
66
	private static $fsSetup = false;
67
68
	protected static function getAppManager() {
69
		return \OC::$server->getAppManager();
70
	}
71
72
	private static function initLocalStorageRootFS() {
73
		// mount local file backend as root
74
		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
75
		//first set up the local "root" storage
76
		\OC\Files\Filesystem::initMountManager();
77
		if (!self::$rootMounted) {
78
			\OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
79
			self::$rootMounted = true;
80
		}
81
	}
82
83
	/**
84
	 * mounting an object storage as the root fs will in essence remove the
85
	 * necessity of a data folder being present.
86
	 * TODO make home storage aware of this and use the object storage instead of local disk access
87
	 *
88
	 * @param array $config containing 'class' and optional 'arguments'
89
	 */
90
	private static function initObjectStoreRootFS($config) {
91
		// check misconfiguration
92
		if (empty($config['class'])) {
93
			\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
94
		}
95
		if (!isset($config['arguments'])) {
96
			$config['arguments'] = array();
97
		}
98
99
		// instantiate object store implementation
100
		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
101
		// mount with plain / root object store implementation
102
		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
103
104
		// mount object storage as root
105
		\OC\Files\Filesystem::initMountManager();
106
		if (!self::$rootMounted) {
107
			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
108
			self::$rootMounted = true;
109
		}
110
	}
111
112
	/**
113
	 * Can be set up
114
	 *
115
	 * @param string $user
116
	 * @return boolean
117
	 * @description configure the initial filesystem based on the configuration
118
	 */
119
	public static function setupFS($user = '') {
120
		//setting up the filesystem twice can only lead to trouble
121
		if (self::$fsSetup) {
122
			return false;
123
		}
124
125
		\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
126
127
		// If we are not forced to load a specific user we load the one that is logged in
128
		if ($user === null) {
129
			$user = '';
130
		} else if ($user == "" && OC_User::isLoggedIn()) {
0 ignored issues
show
Deprecated Code introduced by
The method OC_User::isLoggedIn() has been deprecated with message: use \OC::$server->getUserSession()->isLoggedIn()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
131
			$user = OC_User::getUser();
132
		}
133
134
		// load all filesystem apps before, so no setup-hook gets lost
135
		OC_App::loadApps(array('filesystem'));
136
137
		// the filesystem will finish when $user is not empty,
138
		// mark fs setup here to avoid doing the setup from loading
139
		// OC_Filesystem
140
		if ($user != '') {
141
			self::$fsSetup = true;
142
		}
143
144
		\OC\Files\Filesystem::initMountManager();
145
146
		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
147
		\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
148
			if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
149
				/** @var \OC\Files\Storage\Common $storage */
150
				$storage->setMountOptions($mount->getOptions());
151
			}
152
			return $storage;
153
		});
154
155
		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
156
			if (!$mount->getOption('enable_sharing', true)) {
157
				return new \OC\Files\Storage\Wrapper\PermissionsMask([
158
					'storage' => $storage,
159
					'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
160
				]);
161
			}
162
			return $storage;
163
		});
164
165
		// install storage availability wrapper, before most other wrappers
166
		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
167
			if (!$storage->instanceOfStorage('\OC\Files\Storage\Shared') && !$storage->isLocal()) {
168
				return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
169
			}
170
			return $storage;
171
		});
172
173
		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
174
			if ($mount->getOption('encoding_compatibility', true) && !$storage->instanceOfStorage('\OC\Files\Storage\Shared') && !$storage->isLocal()) {
175
				return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
176
			}
177
			return $storage;
178
		});
179
180
		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
181
			// set up quota for home storages, even for other users
182
			// which can happen when using sharing
183
184
			/**
185
			 * @var \OC\Files\Storage\Storage $storage
186
			 */
187
			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
188
				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
189
			) {
190
				/** @var \OC\Files\Storage\Home $storage */
191
				if (is_object($storage->getUser())) {
192
					$user = $storage->getUser()->getUID();
193
					$quota = OC_Util::getUserQuota($user);
194
					if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
195
						return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
196
					}
197
				}
198
			}
199
200
			return $storage;
201
		});
202
203
		OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
204
		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(true);
205
206
		//check if we are using an object storage
207
		$objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
208
		if (isset($objectStore)) {
209
			self::initObjectStoreRootFS($objectStore);
210
		} else {
211
			self::initLocalStorageRootFS();
212
		}
213
214
		if ($user != '' && !OCP\User::userExists($user)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\User::userExists() has been deprecated with message: 8.1.0 use method userExists() of \OCP\IUserManager - \OC::$server->getUserManager()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
215
			\OC::$server->getEventLogger()->end('setup_fs');
216
			return false;
217
		}
218
219
		//if we aren't logged in, there is no use to set up the filesystem
220
		if ($user != "") {
221
222
			$userDir = '/' . $user . '/files';
223
224
			//jail the user into his "home" directory
225
			\OC\Files\Filesystem::init($user, $userDir);
226
227
			OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
228
		}
229
		\OC::$server->getEventLogger()->end('setup_fs');
230
		return true;
231
	}
232
233
	/**
234
	 * check if a password is required for each public link
235
	 *
236
	 * @return boolean
237
	 */
238
	public static function isPublicLinkPasswordRequired() {
239
		$appConfig = \OC::$server->getAppConfig();
240
		$enforcePassword = $appConfig->getValue('core', 'shareapi_enforce_links_password', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
241
		return ($enforcePassword === 'yes') ? true : false;
242
	}
243
244
	/**
245
	 * check if sharing is disabled for the current user
246
	 * @param IConfig $config
247
	 * @param IGroupManager $groupManager
248
	 * @param IUser|null $user
249
	 * @return bool
250
	 */
251
	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
252
		if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
253
			$groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
254
			$excludedGroups = json_decode($groupsList);
255 View Code Duplication
			if (is_null($excludedGroups)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
				$excludedGroups = explode(',', $groupsList);
257
				$newValue = json_encode($excludedGroups);
258
				$config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
259
			}
260
			$usersGroups = $groupManager->getUserGroupIds($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by parameter $user on line 251 can be null; however, OCP\IGroupManager::getUserGroupIds() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
261 View Code Duplication
			if (!empty($usersGroups)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
				$remainingGroups = array_diff($usersGroups, $excludedGroups);
263
				// if the user is only in groups which are disabled for sharing then
264
				// sharing is also disabled for the user
265
				if (empty($remainingGroups)) {
266
					return true;
267
				}
268
			}
269
		}
270
		return false;
271
	}
272
273
	/**
274
	 * check if share API enforces a default expire date
275
	 *
276
	 * @return boolean
277
	 */
278
	public static function isDefaultExpireDateEnforced() {
279
		$isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
280
		$enforceDefaultExpireDate = false;
281
		if ($isDefaultExpireDateEnabled === 'yes') {
282
			$value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getAppValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
283
			$enforceDefaultExpireDate = ($value === 'yes') ? true : false;
284
		}
285
286
		return $enforceDefaultExpireDate;
287
	}
288
289
	/**
290
	 * Get the quota of a user
291
	 *
292
	 * @param string $user
293
	 * @return int Quota bytes
294
	 */
295
	public static function getUserQuota($user) {
296
		$userQuota = \OC::$server->getUserManager()->get($user)->getQuota();
297
		if($userQuota === 'none') {
298
			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
299
		}else{
300
			return OC_Helper::computerFileSize($userQuota);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression \OC_Helper::computerFileSize($userQuota); of type double|false adds false to the return on line 300 which is incompatible with the return type documented by OC_Util::getUserQuota of type integer. It seems like you forgot to handle an error condition.
Loading history...
301
		}
302
	}
303
304
	/**
305
	 * copies the skeleton to the users /files
306
	 *
307
	 * @param String $userId
308
	 * @param \OCP\Files\Folder $userDirectory
309
	 */
310
	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
311
312
		$skeletonDirectory = \OCP\Config::getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getSystemValue() has been deprecated with message: 8.0.0 use method getSystemValue of \OCP\IConfig This function gets the value from config.php. If it does not exist,
$default will be returned.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
313
314
		if (!empty($skeletonDirectory)) {
315
			\OCP\Util::writeLog(
316
				'files_skeleton',
317
				'copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
318
				\OCP\Util::DEBUG
319
			);
320
			self::copyr($skeletonDirectory, $userDirectory);
321
			// update the file cache
322
			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
323
		}
324
	}
325
326
	/**
327
	 * copies a directory recursively by using streams
328
	 *
329
	 * @param string $source
330
	 * @param \OCP\Files\Folder $target
331
	 * @return void
332
	 */
333
	public static function copyr($source, \OCP\Files\Folder $target) {
334
		$dir = opendir($source);
335
		while (false !== ($file = readdir($dir))) {
336
			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
337
				if (is_dir($source . '/' . $file)) {
338
					$child = $target->newFolder($file);
339
					self::copyr($source . '/' . $file, $child);
340
				} else {
341
					$child = $target->newFile($file);
342
					stream_copy_to_stream(fopen($source . '/' . $file,'r'), $child->fopen('w'));
343
				}
344
			}
345
		}
346
		closedir($dir);
347
	}
348
349
	/**
350
	 * @return void
351
	 */
352
	public static function tearDownFS() {
353
		\OC\Files\Filesystem::tearDown();
354
		self::$fsSetup = false;
355
		self::$rootMounted = false;
356
	}
357
358
	/**
359
	 * get the current installed version of ownCloud
360
	 *
361
	 * @return array
362
	 */
363
	public static function getVersion() {
364
		OC_Util::loadVersion();
365
		return \OC::$server->getSession()->get('OC_Version');
366
	}
367
368
	/**
369
	 * get the current installed version string of ownCloud
370
	 *
371
	 * @return string
372
	 */
373
	public static function getVersionString() {
374
		OC_Util::loadVersion();
375
		return \OC::$server->getSession()->get('OC_VersionString');
376
	}
377
378
	/**
379
	 * @description get the current installed edition of ownCloud. There is the community
380
	 * edition that just returns an empty string and the enterprise edition
381
	 * that returns "Enterprise".
382
	 * @return string
383
	 */
384
	public static function getEditionString() {
385
		if (OC_App::isEnabled('enterprise_key')) {
386
			return "Enterprise";
387
		} else {
388
			return "";
389
		}
390
391
	}
392
393
	/**
394
	 * @description get the update channel of the current installed of ownCloud.
395
	 * @return string
396
	 */
397
	public static function getChannel() {
398
		OC_Util::loadVersion();
399
		return \OC::$server->getSession()->get('OC_Channel');
400
	}
401
402
	/**
403
	 * @description get the build number of the current installed of ownCloud.
404
	 * @return string
405
	 */
406
	public static function getBuild() {
407
		OC_Util::loadVersion();
408
		return \OC::$server->getSession()->get('OC_Build');
409
	}
410
411
	/**
412
	 * @description load the version.php into the session as cache
413
	 */
414
	private static function loadVersion() {
415
		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
416
		if (!\OC::$server->getSession()->exists('OC_Version') or OC::$server->getSession()->get('OC_Version_Timestamp') != $timestamp) {
417
			require OC::$SERVERROOT . '/version.php';
418
			$session = \OC::$server->getSession();
419
			/** @var $timestamp int */
420
			$session->set('OC_Version_Timestamp', $timestamp);
421
			/** @var $OC_Version string */
422
			$session->set('OC_Version', $OC_Version);
0 ignored issues
show
Bug introduced by
The variable $OC_Version does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
423
			/** @var $OC_VersionString string */
424
			$session->set('OC_VersionString', $OC_VersionString);
0 ignored issues
show
Bug introduced by
The variable $OC_VersionString does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
425
			/** @var $OC_Build string */
426
			$session->set('OC_Build', $OC_Build);
0 ignored issues
show
Bug introduced by
The variable $OC_Build does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
427
			
428
			// Allow overriding update channel
429
			
430 View Code Duplication
			if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
431
				$channel = \OC::$server->getAppConfig()->getValue('core', 'OC_Channel');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
432
			} else {
433
				/** @var $OC_Channel string */
434
				$channel = $OC_Channel;
0 ignored issues
show
Bug introduced by
The variable $OC_Channel does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
435
			}
436
			
437
			if (!is_null($channel)) {
438
				$session->set('OC_Channel', $channel);
439
			} else {
440
				/** @var $OC_Channel string */
441
				$session->set('OC_Channel', $OC_Channel);
442
			}
443
		}
444
	}
445
446
	/**
447
	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
448
	 *
449
	 * @param string $application application to get the files from
450
	 * @param string $directory directory within this application (css, js, vendor, etc)
451
	 * @param string $file the file inside of the above folder
452
	 * @return string the path
453
	 */
454
	private static function generatePath($application, $directory, $file) {
455
		if (is_null($file)) {
456
			$file = $application;
457
			$application = "";
458
		}
459
		if (!empty($application)) {
460
			return "$application/$directory/$file";
461
		} else {
462
			return "$directory/$file";
463
		}
464
	}
465
466
	/**
467
	 * add a javascript file
468
	 *
469
	 * @param string $application application id
470
	 * @param string|null $file filename
471
	 * @param bool $prepend prepend the Script to the beginning of the list
472
	 * @return void
473
	 */
474
	public static function addScript($application, $file = null, $prepend = false) {
475
		$path = OC_Util::generatePath($application, 'js', $file);
476
477
		// core js files need separate handling
478
		if ($application !== 'core' && $file !== null) {
479
			self::addTranslations ( $application );
480
		}
481
		self::addExternalResource($application, $prepend, $path, "script");
482
	}
483
484
	/**
485
	 * add a javascript file from the vendor sub folder
486
	 *
487
	 * @param string $application application id
488
	 * @param string|null $file filename
489
	 * @param bool $prepend prepend the Script to the beginning of the list
490
	 * @return void
491
	 */
492
	public static function addVendorScript($application, $file = null, $prepend = false) {
493
		$path = OC_Util::generatePath($application, 'vendor', $file);
494
		self::addExternalResource($application, $prepend, $path, "script");
495
	}
496
497
	/**
498
	 * add a translation JS file
499
	 *
500
	 * @param string $application application id
501
	 * @param string $languageCode language code, defaults to the current language
502
	 * @param bool $prepend prepend the Script to the beginning of the list 
503
	 */
504
	public static function addTranslations($application, $languageCode = null, $prepend = false) {
505
		if (is_null($languageCode)) {
506
			$languageCode = \OC_L10N::findLanguage($application);
0 ignored issues
show
Deprecated Code introduced by
The method OC_L10N::findLanguage() has been deprecated with message: 9.0.0 Use \OC::$server->getL10NFactory()->findLanguage() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
507
		}
508
		if (!empty($application)) {
509
			$path = "$application/l10n/$languageCode";
510
		} else {
511
			$path = "l10n/$languageCode";
512
		}
513
		self::addExternalResource($application, $prepend, $path, "script");
514
	}
515
516
	/**
517
	 * add a css file
518
	 *
519
	 * @param string $application application id
520
	 * @param string|null $file filename
521
	 * @param bool $prepend prepend the Style to the beginning of the list
522
	 * @return void
523
	 */
524
	public static function addStyle($application, $file = null, $prepend = false) {
525
		$path = OC_Util::generatePath($application, 'css', $file);
526
		self::addExternalResource($application, $prepend, $path, "style");
527
	}
528
529
	/**
530
	 * add a css file from the vendor sub folder
531
	 *
532
	 * @param string $application application id
533
	 * @param string|null $file filename
534
	 * @param bool $prepend prepend the Style to the beginning of the list
535
	 * @return void
536
	 */
537
	public static function addVendorStyle($application, $file = null, $prepend = false) {
538
		$path = OC_Util::generatePath($application, 'vendor', $file);
539
		self::addExternalResource($application, $prepend, $path, "style");
540
	}
541
542
	/**
543
	 * add an external resource css/js file
544
	 *
545
	 * @param string $application application id
546
	 * @param bool $prepend prepend the file to the beginning of the list
547
	 * @param string $path 
548
	 * @param string $type (script or style)
549
	 * @return void
550
	 */
551
	private static function addExternalResource($application, $prepend, $path, $type = "script") {
0 ignored issues
show
Unused Code introduced by
The parameter $application is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
552
553
		if ($type === "style") {
554 View Code Duplication
			if (!in_array($path, self::$styles)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
555
				if ($prepend === true) {
556
					array_unshift ( self::$styles, $path );
557
				} else {
558
					self::$styles[] = $path;
559
				}
560
			}
561 View Code Duplication
		} elseif ($type === "script") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
562
			if (!in_array($path, self::$scripts)) {
563
				if ($prepend === true) {
564
					array_unshift ( self::$scripts, $path );
565
				} else {
566
					self::$scripts [] = $path;
567
				}
568
			}
569
		}
570
	}
571
572
	/**
573
	 * Add a custom element to the header
574
	 * If $text is null then the element will be written as empty element.
575
	 * So use "" to get a closing tag.
576
	 * @param string $tag tag name of the element
577
	 * @param array $attributes array of attributes for the element
578
	 * @param string $text the text content for the element
579
	 */
580 View Code Duplication
	public static function addHeader($tag, $attributes, $text=null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
581
		self::$headers[] = array(
582
			'tag' => $tag,
583
			'attributes' => $attributes,
584
			'text' => $text
585
		);
586
	}
587
588
	/**
589
	 * formats a timestamp in the "right" way
590
	 *
591
	 * @param int $timestamp
592
	 * @param bool $dateOnly option to omit time from the result
593
	 * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
594
	 * @return string timestamp
595
	 *
596
	 * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
597
	 */
598
	public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
599
		if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
600
			$timeZone = new \DateTimeZone($timeZone);
601
		}
602
603
		/** @var \OC\DateTimeFormatter $formatter */
604
		$formatter = \OC::$server->query('DateTimeFormatter');
605
		if ($dateOnly) {
606
			return $formatter->formatDate($timestamp, 'long', $timeZone);
607
		}
608
		return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
609
	}
610
611
	/**
612
	 * check if the current server configuration is suitable for ownCloud
613
	 *
614
	 * @param \OCP\IConfig $config
615
	 * @return array arrays with error messages and hints
616
	 */
617
	public static function checkServer(\OCP\IConfig $config) {
618
		$l = \OC::$server->getL10N('lib');
619
		$errors = array();
620
		$CONFIG_DATADIRECTORY = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data');
621
622
		if (!self::needUpgrade($config) && $config->getSystemValue('installed', false)) {
623
			// this check needs to be done every time
624
			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
625
		}
626
627
		// Assume that if checkServer() succeeded before in this session, then all is fine.
628
		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
629
			return $errors;
630
		}
631
632
		$webServerRestart = false;
633
		$setup = new \OC\Setup($config, \OC::$server->getIniWrapper(), \OC::$server->getL10N('lib'),
634
			new \OC_Defaults(), \OC::$server->getLogger(), \OC::$server->getSecureRandom());
635
636
		$urlGenerator = \OC::$server->getURLGenerator();
637
638
		$availableDatabases = $setup->getSupportedDatabases();
639
		if (empty($availableDatabases)) {
640
			$errors[] = array(
641
				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
642
				'hint' => '' //TODO: sane hint
643
			);
644
			$webServerRestart = true;
645
		}
646
647
		// Check if server running on Windows platform
648 View Code Duplication
		if(OC_Util::runningOnWindows()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
649
			$errors[] = [
650
				'error' => $l->t('Microsoft Windows Platform is not supported'),
651
				'hint' => $l->t('Running Nextcloud Server on the Microsoft Windows platform is not supported. We suggest you ' .
652
					'use a Linux server in a virtual machine if you have no option for migrating the server itself.')
653
			];
654
		}
655
656
		// Check if config folder is writable.
657
		if(!OC_Helper::isReadOnlyConfigEnabled()) {
658
			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
659
				$errors[] = array(
660
					'error' => $l->t('Cannot write into "config" directory'),
661
					'hint' => $l->t('This can usually be fixed by '
662
						. '%sgiving the webserver write access to the config directory%s.',
663
						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
664
				);
665
			}
666
		}
667
668
		// Check if there is a writable install folder.
669
		if ($config->getSystemValue('appstoreenabled', true)) {
670
			if (OC_App::getInstallPath() === null
671
				|| !is_writable(OC_App::getInstallPath())
672
				|| !is_readable(OC_App::getInstallPath())
673
			) {
674
				$errors[] = array(
675
					'error' => $l->t('Cannot write into "apps" directory'),
676
					'hint' => $l->t('This can usually be fixed by '
677
						. '%sgiving the webserver write access to the apps directory%s'
678
						. ' or disabling the appstore in the config file.',
679
						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
680
				);
681
			}
682
		}
683
		// Create root dir.
684
		if ($config->getSystemValue('installed', false)) {
685
			if (!is_dir($CONFIG_DATADIRECTORY)) {
686
				$success = @mkdir($CONFIG_DATADIRECTORY);
687
				if ($success) {
688
					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
689
				} else {
690
					$errors[] = array(
691
						'error' => $l->t('Cannot create "data" directory (%s)', array($CONFIG_DATADIRECTORY)),
692
						'hint' => $l->t('This can usually be fixed by '
693
							. '<a href="%s" target="_blank" rel="noreferrer">giving the webserver write access to the root directory</a>.',
694
							array($urlGenerator->linkToDocs('admin-dir_permissions')))
695
					);
696
				}
697
			} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
698
				//common hint for all file permissions error messages
699
				$permissionsHint = $l->t('Permissions can usually be fixed by '
700
					. '%sgiving the webserver write access to the root directory%s.',
701
					array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'));
702
				$errors[] = array(
703
					'error' => 'Data directory (' . $CONFIG_DATADIRECTORY . ') not writable',
704
					'hint' => $permissionsHint
705
				);
706
			} else {
707
				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
708
			}
709
		}
710
711 View Code Duplication
		if (!OC_Util::isSetLocaleWorking()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
712
			$errors[] = array(
713
				'error' => $l->t('Setting locale to %s failed',
714
					array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
715
						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
716
				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
717
			);
718
		}
719
720
		// Contains the dependencies that should be checked against
721
		// classes = class_exists
722
		// functions = function_exists
723
		// defined = defined
724
		// ini = ini_get
725
		// If the dependency is not found the missing module name is shown to the EndUser
726
		// When adding new checks always verify that they pass on Travis as well
727
		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
728
		$dependencies = array(
729
			'classes' => array(
730
				'ZipArchive' => 'zip',
731
				'DOMDocument' => 'dom',
732
				'XMLWriter' => 'XMLWriter',
733
				'XMLReader' => 'XMLReader',
734
			),
735
			'functions' => [
736
				'xml_parser_create' => 'libxml',
737
				'mb_strcut' => 'mb multibyte',
738
				'ctype_digit' => 'ctype',
739
				'json_encode' => 'JSON',
740
				'gd_info' => 'GD',
741
				'gzencode' => 'zlib',
742
				'iconv' => 'iconv',
743
				'simplexml_load_string' => 'SimpleXML',
744
				'hash' => 'HASH Message Digest Framework',
745
				'curl_init' => 'cURL',
746
			],
747
			'defined' => array(
748
				'PDO::ATTR_DRIVER_NAME' => 'PDO'
749
			),
750
			'ini' => [
751
				'default_charset' => 'UTF-8',
752
			],
753
		);
754
		$missingDependencies = array();
755
		$invalidIniSettings = [];
756
		$moduleHint = $l->t('Please ask your server administrator to install the module.');
757
758
		/**
759
		 * FIXME: The dependency check does not work properly on HHVM on the moment
760
		 *        and prevents installation. Once HHVM is more compatible with our
761
		 *        approach to check for these values we should re-enable those
762
		 *        checks.
763
		 */
764
		$iniWrapper = \OC::$server->getIniWrapper();
765
		if (!self::runningOnHhvm()) {
766
			foreach ($dependencies['classes'] as $class => $module) {
767
				if (!class_exists($class)) {
768
					$missingDependencies[] = $module;
769
				}
770
			}
771
			foreach ($dependencies['functions'] as $function => $module) {
772
				if (!function_exists($function)) {
773
					$missingDependencies[] = $module;
774
				}
775
			}
776
			foreach ($dependencies['defined'] as $defined => $module) {
777
				if (!defined($defined)) {
778
					$missingDependencies[] = $module;
779
				}
780
			}
781
			foreach ($dependencies['ini'] as $setting => $expected) {
782
				if (is_bool($expected)) {
783
					if ($iniWrapper->getBool($setting) !== $expected) {
784
						$invalidIniSettings[] = [$setting, $expected];
785
					}
786
				}
787
				if (is_int($expected)) {
788
					if ($iniWrapper->getNumeric($setting) !== $expected) {
789
						$invalidIniSettings[] = [$setting, $expected];
790
					}
791
				}
792
				if (is_string($expected)) {
793
					if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
794
						$invalidIniSettings[] = [$setting, $expected];
795
					}
796
				}
797
			}
798
		}
799
800
		foreach($missingDependencies as $missingDependency) {
801
			$errors[] = array(
802
				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
803
				'hint' => $moduleHint
804
			);
805
			$webServerRestart = true;
806
		}
807
		foreach($invalidIniSettings as $setting) {
808
			if(is_bool($setting[1])) {
809
				$setting[1] = ($setting[1]) ? 'on' : 'off';
810
			}
811
			$errors[] = [
812
				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
813
				'hint' =>  $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
814
			];
815
			$webServerRestart = true;
816
		}
817
818
		/**
819
		 * The mbstring.func_overload check can only be performed if the mbstring
820
		 * module is installed as it will return null if the checking setting is
821
		 * not available and thus a check on the boolean value fails.
822
		 *
823
		 * TODO: Should probably be implemented in the above generic dependency
824
		 *       check somehow in the long-term.
825
		 */
826
		if($iniWrapper->getBool('mbstring.func_overload') !== null &&
827
			$iniWrapper->getBool('mbstring.func_overload') === true) {
828
			$errors[] = array(
829
				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
830
				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
831
			);
832
		}
833
834
		if(function_exists('xml_parser_create') &&
835
			version_compare('2.7.0', LIBXML_DOTTED_VERSION) === 1) {
836
			$errors[] = array(
837
				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [LIBXML_DOTTED_VERSION]),
838
				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
839
			);
840
		}
841
842
		if (!self::isAnnotationsWorking()) {
843
			$errors[] = array(
844
				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
845
				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
846
			);
847
		}
848
849
		if (!\OC::$CLI && $webServerRestart) {
850
			$errors[] = array(
851
				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
852
				'hint' => $l->t('Please ask your server administrator to restart the web server.')
853
			);
854
		}
855
856
		$errors = array_merge($errors, self::checkDatabaseVersion());
857
858
		// Cache the result of this function
859
		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
860
861
		return $errors;
862
	}
863
864
	/**
865
	 * Check the database version
866
	 *
867
	 * @return array errors array
868
	 */
869
	public static function checkDatabaseVersion() {
870
		$l = \OC::$server->getL10N('lib');
871
		$errors = array();
872
		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
873
		if ($dbType === 'pgsql') {
874
			// check PostgreSQL version
875
			try {
876
				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
877
				$data = $result->fetchRow();
878
				if (isset($data['server_version'])) {
879
					$version = $data['server_version'];
880
					if (version_compare($version, '9.0.0', '<')) {
881
						$errors[] = array(
882
							'error' => $l->t('PostgreSQL >= 9 required'),
883
							'hint' => $l->t('Please upgrade your database version')
884
						);
885
					}
886
				}
887
			} catch (\Doctrine\DBAL\DBALException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\DBALException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
888
				$logger = \OC::$server->getLogger();
889
				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
890
				$logger->logException($e);
891
			}
892
		}
893
		return $errors;
894
	}
895
896
	/**
897
	 * Check for correct file permissions of data directory
898
	 *
899
	 * @param string $dataDirectory
900
	 * @return array arrays with error messages and hints
901
	 */
902
	public static function checkDataDirectoryPermissions($dataDirectory) {
903
		$l = \OC::$server->getL10N('lib');
904
		$errors = array();
905
		$permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
906
			. ' cannot be listed by other users.');
907
		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
908
		if (substr($perms, -1) != '0') {
909
			chmod($dataDirectory, 0770);
910
			clearstatcache();
911
			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
912 View Code Duplication
			if (substr($perms, 2, 1) != '0') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
913
				$errors[] = array(
914
					'error' => $l->t('Data directory (%s) is readable by other users', array($dataDirectory)),
915
					'hint' => $permissionsModHint
916
				);
917
			}
918
		}
919
		return $errors;
920
	}
921
922
	/**
923
	 * Check that the data directory exists and is valid by
924
	 * checking the existence of the ".ocdata" file.
925
	 *
926
	 * @param string $dataDirectory data directory path
927
	 * @return array errors found
928
	 */
929
	public static function checkDataDirectoryValidity($dataDirectory) {
930
		$l = \OC::$server->getL10N('lib');
931
		$errors = [];
932 View Code Duplication
		if ($dataDirectory[0] !== '/') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
933
			$errors[] = [
934
				'error' => $l->t('Data directory (%s) must be an absolute path', [$dataDirectory]),
935
				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
936
			];
937
		}
938 View Code Duplication
		if (!file_exists($dataDirectory . '/.ocdata')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
939
			$errors[] = [
940
				'error' => $l->t('Data directory (%s) is invalid', [$dataDirectory]),
941
				'hint' => $l->t('Please check that the data directory contains a file' .
942
					' ".ocdata" in its root.')
943
			];
944
		}
945
		return $errors;
946
	}
947
948
	/**
949
	 * Check if the user is logged in, redirects to home if not. With
950
	 * redirect URL parameter to the request URI.
951
	 *
952
	 * @return void
953
	 */
954
	public static function checkLoggedIn() {
955
		// Check if we are a user
956
		if (!OC_User::isLoggedIn()) {
0 ignored issues
show
Deprecated Code introduced by
The method OC_User::isLoggedIn() has been deprecated with message: use \OC::$server->getUserSession()->isLoggedIn()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
957
			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
958
						'core.login.showLoginForm',
959
						[
960
							'redirect_url' => urlencode(\OC::$server->getRequest()->getRequestUri()),
961
						]
962
					)
963
			);
964
			exit();
965
		}
966
		// Redirect to index page if 2FA challenge was not solved yet
967
		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor()) {
968
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
969
			exit();
970
		}
971
	}
972
973
	/**
974
	 * Check if the user is a admin, redirects to home if not
975
	 *
976
	 * @return void
977
	 */
978
	public static function checkAdminUser() {
979
		OC_Util::checkLoggedIn();
980
		if (!OC_User::isAdminUser(OC_User::getUser())) {
981
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
982
			exit();
983
		}
984
	}
985
986
	/**
987
	 * Check if it is allowed to remember login.
988
	 *
989
	 * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature
990
	 *
991
	 * @return bool
992
	 */
993
	public static function rememberLoginAllowed() {
994
995
		$apps = OC_App::getEnabledApps();
996
997
		foreach ($apps as $app) {
998
			$appInfo = OC_App::getAppInfo($app);
999
			if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') {
1000
				return false;
1001
			}
1002
1003
		}
1004
		return true;
1005
	}
1006
1007
	/**
1008
	 * Check if the user is a subadmin, redirects to home if not
1009
	 *
1010
	 * @return null|boolean $groups where the current user is subadmin
1011
	 */
1012
	public static function checkSubAdminUser() {
1013
		OC_Util::checkLoggedIn();
1014
		$userObject = \OC::$server->getUserSession()->getUser();
1015
		$isSubAdmin = false;
1016
		if($userObject !== null) {
1017
			$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1018
		}
1019
1020
		if (!$isSubAdmin) {
1021
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1022
			exit();
1023
		}
1024
		return true;
1025
	}
1026
1027
	/**
1028
	 * Returns the URL of the default page
1029
	 * based on the system configuration and
1030
	 * the apps visible for the current user
1031
	 *
1032
	 * @return string URL
1033
	 */
1034
	public static function getDefaultPageUrl() {
1035
		$urlGenerator = \OC::$server->getURLGenerator();
1036
		// Deny the redirect if the URL contains a @
1037
		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
1038
		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1039
			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1040
		} else {
1041
			$defaultPage = \OC::$server->getAppConfig()->getValue('core', 'defaultpage');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1042
			if ($defaultPage) {
1043
				$location = $urlGenerator->getAbsoluteURL($defaultPage);
1044
			} else {
1045
				$appId = 'files';
1046
				$defaultApps = explode(',', \OCP\Config::getSystemValue('defaultapp', 'files'));
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Config::getSystemValue() has been deprecated with message: 8.0.0 use method getSystemValue of \OCP\IConfig This function gets the value from config.php. If it does not exist,
$default will be returned.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1047
				// find the first app that is enabled for the current user
1048
				foreach ($defaultApps as $defaultApp) {
1049
					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1050
					if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1051
						$appId = $defaultApp;
1052
						break;
1053
					}
1054
				}
1055
1056
				if(getenv('front_controller_active') === 'true') {
1057
					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1058
				} else {
1059
					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1060
				}
1061
			}
1062
		}
1063
		return $location;
1064
	}
1065
1066
	/**
1067
	 * Redirect to the user default page
1068
	 *
1069
	 * @return void
1070
	 */
1071
	public static function redirectToDefaultPage() {
1072
		$location = self::getDefaultPageUrl();
1073
		header('Location: ' . $location);
1074
		exit();
1075
	}
1076
1077
	/**
1078
	 * get an id unique for this instance
1079
	 *
1080
	 * @return string
1081
	 */
1082
	public static function getInstanceId() {
1083
		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1084
		if (is_null($id)) {
1085
			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1086
			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1087
			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1088
		}
1089
		return $id;
1090
	}
1091
1092
	/**
1093
	 * Public function to sanitize HTML
1094
	 *
1095
	 * This function is used to sanitize HTML and should be applied on any
1096
	 * string or array of strings before displaying it on a web page.
1097
	 *
1098
	 * @param string|array $value
1099
	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1100
	 */
1101
	public static function sanitizeHTML($value) {
1102
		if (is_array($value)) {
1103
			$value = array_map(function($value) {
1104
				return self::sanitizeHTML($value);
1105
			}, $value);
1106
		} else {
1107
			// Specify encoding for PHP<5.4
1108
			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1109
		}
1110
		return $value;
1111
	}
1112
1113
	/**
1114
	 * Public function to encode url parameters
1115
	 *
1116
	 * This function is used to encode path to file before output.
1117
	 * Encoding is done according to RFC 3986 with one exception:
1118
	 * Character '/' is preserved as is.
1119
	 *
1120
	 * @param string $component part of URI to encode
1121
	 * @return string
1122
	 */
1123
	public static function encodePath($component) {
1124
		$encoded = rawurlencode($component);
1125
		$encoded = str_replace('%2F', '/', $encoded);
1126
		return $encoded;
1127
	}
1128
1129
1130
	public function createHtaccessTestFile(\OCP\IConfig $config) {
1131
		// php dev server does not support htaccess
1132
		if (php_sapi_name() === 'cli-server') {
1133
			return false;
1134
		}
1135
1136
		// testdata
1137
		$fileName = '/htaccesstest.txt';
1138
		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1139
1140
		// creating a test file
1141
		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1142
1143
		if (file_exists($testFile)) {// already running this test, possible recursive call
1144
			return false;
1145
		}
1146
1147
		$fp = @fopen($testFile, 'w');
1148
		if (!$fp) {
1149
			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1150
				'Make sure it is possible for the webserver to write to ' . $testFile);
1151
		}
1152
		fwrite($fp, $testContent);
1153
		fclose($fp);
1154
	}
1155
1156
	/**
1157
	 * Check if the .htaccess file is working
1158
	 * @param \OCP\IConfig $config
1159
	 * @return bool
1160
	 * @throws Exception
1161
	 * @throws \OC\HintException If the test file can't get written.
1162
	 */
1163
	public function isHtaccessWorking(\OCP\IConfig $config) {
1164
1165
		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1166
			return true;
1167
		}
1168
1169
		$testContent = $this->createHtaccessTestFile($config);
1170
		if ($testContent === false) {
1171
			return false;
1172
		}
1173
1174
		$fileName = '/htaccesstest.txt';
1175
		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1176
1177
		// accessing the file via http
1178
		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1179
		try {
1180
			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1181
		} catch (\Exception $e) {
1182
			$content = false;
1183
		}
1184
1185
		// cleanup
1186
		@unlink($testFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1187
1188
		/*
1189
		 * If the content is not equal to test content our .htaccess
1190
		 * is working as required
1191
		 */
1192
		return $content !== $testContent;
1193
	}
1194
1195
	/**
1196
	 * Check if the setlocal call does not work. This can happen if the right
1197
	 * local packages are not available on the server.
1198
	 *
1199
	 * @return bool
1200
	 */
1201
	public static function isSetLocaleWorking() {
1202
		\Patchwork\Utf8\Bootup::initLocale();
1203
		if ('' === basename('§')) {
1204
			return false;
1205
		}
1206
		return true;
1207
	}
1208
1209
	/**
1210
	 * Check if it's possible to get the inline annotations
1211
	 *
1212
	 * @return bool
1213
	 */
1214
	public static function isAnnotationsWorking() {
1215
		$reflection = new \ReflectionMethod(__METHOD__);
1216
		$docs = $reflection->getDocComment();
1217
1218
		return (is_string($docs) && strlen($docs) > 50);
1219
	}
1220
1221
	/**
1222
	 * Check if the PHP module fileinfo is loaded.
1223
	 *
1224
	 * @return bool
1225
	 */
1226
	public static function fileInfoLoaded() {
1227
		return function_exists('finfo_open');
1228
	}
1229
1230
	/**
1231
	 * clear all levels of output buffering
1232
	 *
1233
	 * @return void
1234
	 */
1235
	public static function obEnd() {
1236
		while (ob_get_level()) {
1237
			ob_end_clean();
1238
		}
1239
	}
1240
1241
	/**
1242
	 * Checks whether the server is running on Windows
1243
	 *
1244
	 * @return bool true if running on Windows, false otherwise
1245
	 */
1246
	public static function runningOnWindows() {
1247
		return (substr(PHP_OS, 0, 3) === "WIN");
1248
	}
1249
1250
	/**
1251
	 * Checks whether the server is running on Mac OS X
1252
	 *
1253
	 * @return bool true if running on Mac OS X, false otherwise
1254
	 */
1255
	public static function runningOnMac() {
1256
		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1257
	}
1258
1259
	/**
1260
	 * Checks whether server is running on HHVM
1261
	 *
1262
	 * @return bool True if running on HHVM, false otherwise
1263
	 */
1264
	public static function runningOnHhvm() {
1265
		return defined('HHVM_VERSION');
1266
	}
1267
1268
	/**
1269
	 * Handles the case that there may not be a theme, then check if a "default"
1270
	 * theme exists and take that one
1271
	 *
1272
	 * @return string the theme
1273
	 */
1274
	public static function getTheme() {
1275
		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1276
1277
		if ($theme === '') {
1278
			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1279
				$theme = 'default';
1280
			}
1281
		}
1282
1283
		return $theme;
1284
	}
1285
1286
	/**
1287
	 * Clear a single file from the opcode cache
1288
	 * This is useful for writing to the config file
1289
	 * in case the opcode cache does not re-validate files
1290
	 * Returns true if successful, false if unsuccessful:
1291
	 * caller should fall back on clearing the entire cache
1292
	 * with clearOpcodeCache() if unsuccessful
1293
	 *
1294
	 * @param string $path the path of the file to clear from the cache
1295
	 * @return bool true if underlying function returns true, otherwise false
1296
	 */
1297
	public static function deleteFromOpcodeCache($path) {
1298
		$ret = false;
1299
		if ($path) {
1300
			// APC >= 3.1.1
1301
			if (function_exists('apc_delete_file')) {
1302
				$ret = @apc_delete_file($path);
1303
			}
1304
			// Zend OpCache >= 7.0.0, PHP >= 5.5.0
1305
			if (function_exists('opcache_invalidate')) {
1306
				$ret = opcache_invalidate($path);
1307
			}
1308
		}
1309
		return $ret;
1310
	}
1311
1312
	/**
1313
	 * Clear the opcode cache if one exists
1314
	 * This is necessary for writing to the config file
1315
	 * in case the opcode cache does not re-validate files
1316
	 *
1317
	 * @return void
1318
	 */
1319
	public static function clearOpcodeCache() {
1320
		// APC
1321
		if (function_exists('apc_clear_cache')) {
1322
			apc_clear_cache();
1323
		}
1324
		// Zend Opcache
1325
		if (function_exists('accelerator_reset')) {
1326
			accelerator_reset();
1327
		}
1328
		// XCache
1329
		if (function_exists('xcache_clear_cache')) {
1330
			if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1331
				\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1332
			} else {
1333
				@xcache_clear_cache(XC_TYPE_PHP, 0);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1334
			}
1335
		}
1336
		// Opcache (PHP >= 5.5)
1337
		if (function_exists('opcache_reset')) {
1338
			opcache_reset();
1339
		}
1340
	}
1341
1342
	/**
1343
	 * Normalize a unicode string
1344
	 *
1345
	 * @param string $value a not normalized string
1346
	 * @return bool|string
1347
	 */
1348
	public static function normalizeUnicode($value) {
1349
		if(Normalizer::isNormalized($value)) {
1350
			return $value;
1351
		}
1352
1353
		$normalizedValue = Normalizer::normalize($value);
1354
		if ($normalizedValue === null || $normalizedValue === false) {
1355
			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1356
			return $value;
1357
		}
1358
1359
		return $normalizedValue;
1360
	}
1361
1362
	/**
1363
	 * @param boolean|string $file
1364
	 * @return string
1365
	 */
1366
	public static function basename($file) {
1367
		$file = rtrim($file, '/');
1368
		$t = explode('/', $file);
1369
		return array_pop($t);
1370
	}
1371
1372
	/**
1373
	 * A human readable string is generated based on version, channel and build number
1374
	 *
1375
	 * @return string
1376
	 */
1377
	public static function getHumanVersion() {
1378
		$version = OC_Util::getVersionString() . ' (' . OC_Util::getChannel() . ')';
1379
		$build = OC_Util::getBuild();
1380
		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1381
			$version .= ' Build:' . $build;
1382
		}
1383
		return $version;
1384
	}
1385
1386
	/**
1387
	 * Returns whether the given file name is valid
1388
	 *
1389
	 * @param string $file file name to check
1390
	 * @return bool true if the file name is valid, false otherwise
1391
	 * @deprecated use \OC\Files\View::verifyPath()
1392
	 */
1393
	public static function isValidFileName($file) {
1394
		$trimmed = trim($file);
1395
		if ($trimmed === '') {
1396
			return false;
1397
		}
1398
		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1399
			return false;
1400
		}
1401
		foreach (str_split($trimmed) as $char) {
1402
			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1403
				return false;
1404
			}
1405
		}
1406
		return true;
1407
	}
1408
1409
	/**
1410
	 * Check whether the instance needs to perform an upgrade,
1411
	 * either when the core version is higher or any app requires
1412
	 * an upgrade.
1413
	 *
1414
	 * @param \OCP\IConfig $config
1415
	 * @return bool whether the core or any app needs an upgrade
1416
	 * @throws \OC\HintException When the upgrade from the given version is not allowed
1417
	 */
1418
	public static function needUpgrade(\OCP\IConfig $config) {
1419
		if ($config->getSystemValue('installed', false)) {
1420
			$installedVersion = $config->getSystemValue('version', '0.0.0');
1421
			$currentVersion = implode('.', \OCP\Util::getVersion());
1422
			$versionDiff = version_compare($currentVersion, $installedVersion);
1423
			if ($versionDiff > 0) {
1424
				return true;
1425
			} else if ($config->getSystemValue('debug', false) && $versionDiff < 0) {
1426
				// downgrade with debug
1427
				$installedMajor = explode('.', $installedVersion);
1428
				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1429
				$currentMajor = explode('.', $currentVersion);
1430
				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1431
				if ($installedMajor === $currentMajor) {
1432
					// Same major, allow downgrade for developers
1433
					return true;
1434
				} else {
1435
					// downgrade attempt, throw exception
1436
					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1437
				}
1438
			} else if ($versionDiff < 0) {
1439
				// downgrade attempt, throw exception
1440
				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1441
			}
1442
1443
			// also check for upgrades for apps (independently from the user)
1444
			$apps = \OC_App::getEnabledApps(false, true);
1445
			$shouldUpgrade = false;
1446
			foreach ($apps as $app) {
1447
				if (\OC_App::shouldUpgrade($app)) {
1448
					$shouldUpgrade = true;
1449
					break;
1450
				}
1451
			}
1452
			return $shouldUpgrade;
1453
		} else {
1454
			return false;
1455
		}
1456
	}
1457
1458
}
1459