Completed
Push — master ( 281937...5a0dc1 )
by Blizzz
34s
created

OC_Util::isPublicLinkPasswordRequired()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
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
		if(OC_Util::runningOnWindows()) {
649
			$errors[] = [
650
				'error' => $l->t('Microsoft Windows Platform is not supported'),
651
				'hint' => $l->t('Running ownCloud 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
					'Find Linux packages as well as easy to deploy virtual machine images on <a href="%s">%s</a>. ' .
654
					'For migrating existing installations to Linux you can find some tips and a migration script ' .
655
					'in <a href="%s">our documentation</a>.',
656
					['https://owncloud.org/install/', 'owncloud.org/install/', 'https://owncloud.org/?p=8045'])
657
			];
658
		}
659
660
		// Check if config folder is writable.
661
		if(!OC_Helper::isReadOnlyConfigEnabled()) {
662
			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
663
				$errors[] = array(
664
					'error' => $l->t('Cannot write into "config" directory'),
665
					'hint' => $l->t('This can usually be fixed by '
666
						. '%sgiving the webserver write access to the config directory%s.',
667
						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
668
				);
669
			}
670
		}
671
672
		// Check if there is a writable install folder.
673
		if ($config->getSystemValue('appstoreenabled', true)) {
674
			if (OC_App::getInstallPath() === null
675
				|| !is_writable(OC_App::getInstallPath())
676
				|| !is_readable(OC_App::getInstallPath())
677
			) {
678
				$errors[] = array(
679
					'error' => $l->t('Cannot write into "apps" directory'),
680
					'hint' => $l->t('This can usually be fixed by '
681
						. '%sgiving the webserver write access to the apps directory%s'
682
						. ' or disabling the appstore in the config file.',
683
						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
684
				);
685
			}
686
		}
687
		// Create root dir.
688
		if ($config->getSystemValue('installed', false)) {
689
			if (!is_dir($CONFIG_DATADIRECTORY)) {
690
				$success = @mkdir($CONFIG_DATADIRECTORY);
691
				if ($success) {
692
					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
693
				} else {
694
					$errors[] = array(
695
						'error' => $l->t('Cannot create "data" directory (%s)', array($CONFIG_DATADIRECTORY)),
696
						'hint' => $l->t('This can usually be fixed by '
697
							. '<a href="%s" target="_blank" rel="noreferrer">giving the webserver write access to the root directory</a>.',
698
							array($urlGenerator->linkToDocs('admin-dir_permissions')))
699
					);
700
				}
701
			} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
702
				//common hint for all file permissions error messages
703
				$permissionsHint = $l->t('Permissions can usually be fixed by '
704
					. '%sgiving the webserver write access to the root directory%s.',
705
					array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'));
706
				$errors[] = array(
707
					'error' => 'Data directory (' . $CONFIG_DATADIRECTORY . ') not writable by ownCloud',
708
					'hint' => $permissionsHint
709
				);
710
			} else {
711
				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
712
			}
713
		}
714
715
		if (!OC_Util::isSetLocaleWorking()) {
716
			$errors[] = array(
717
				'error' => $l->t('Setting locale to %s failed',
718
					array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
719
						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
720
				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
721
			);
722
		}
723
724
		// Contains the dependencies that should be checked against
725
		// classes = class_exists
726
		// functions = function_exists
727
		// defined = defined
728
		// ini = ini_get
729
		// If the dependency is not found the missing module name is shown to the EndUser
730
		// When adding new checks always verify that they pass on Travis as well
731
		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
732
		$dependencies = array(
733
			'classes' => array(
734
				'ZipArchive' => 'zip',
735
				'DOMDocument' => 'dom',
736
				'XMLWriter' => 'XMLWriter',
737
				'XMLReader' => 'XMLReader',
738
			),
739
			'functions' => [
740
				'xml_parser_create' => 'libxml',
741
				'mb_strcut' => 'mb multibyte',
742
				'ctype_digit' => 'ctype',
743
				'json_encode' => 'JSON',
744
				'gd_info' => 'GD',
745
				'gzencode' => 'zlib',
746
				'iconv' => 'iconv',
747
				'simplexml_load_string' => 'SimpleXML',
748
				'hash' => 'HASH Message Digest Framework',
749
				'curl_init' => 'cURL',
750
			],
751
			'defined' => array(
752
				'PDO::ATTR_DRIVER_NAME' => 'PDO'
753
			),
754
			'ini' => [
755
				'default_charset' => 'UTF-8',
756
			],
757
		);
758
		$missingDependencies = array();
759
		$invalidIniSettings = [];
760
		$moduleHint = $l->t('Please ask your server administrator to install the module.');
761
762
		/**
763
		 * FIXME: The dependency check does not work properly on HHVM on the moment
764
		 *        and prevents installation. Once HHVM is more compatible with our
765
		 *        approach to check for these values we should re-enable those
766
		 *        checks.
767
		 */
768
		$iniWrapper = \OC::$server->getIniWrapper();
769
		if (!self::runningOnHhvm()) {
770
			foreach ($dependencies['classes'] as $class => $module) {
771
				if (!class_exists($class)) {
772
					$missingDependencies[] = $module;
773
				}
774
			}
775
			foreach ($dependencies['functions'] as $function => $module) {
776
				if (!function_exists($function)) {
777
					$missingDependencies[] = $module;
778
				}
779
			}
780
			foreach ($dependencies['defined'] as $defined => $module) {
781
				if (!defined($defined)) {
782
					$missingDependencies[] = $module;
783
				}
784
			}
785
			foreach ($dependencies['ini'] as $setting => $expected) {
786
				if (is_bool($expected)) {
787
					if ($iniWrapper->getBool($setting) !== $expected) {
788
						$invalidIniSettings[] = [$setting, $expected];
789
					}
790
				}
791
				if (is_int($expected)) {
792
					if ($iniWrapper->getNumeric($setting) !== $expected) {
793
						$invalidIniSettings[] = [$setting, $expected];
794
					}
795
				}
796
				if (is_string($expected)) {
797
					if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
798
						$invalidIniSettings[] = [$setting, $expected];
799
					}
800
				}
801
			}
802
		}
803
804
		foreach($missingDependencies as $missingDependency) {
805
			$errors[] = array(
806
				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
807
				'hint' => $moduleHint
808
			);
809
			$webServerRestart = true;
810
		}
811
		foreach($invalidIniSettings as $setting) {
812
			if(is_bool($setting[1])) {
813
				$setting[1] = ($setting[1]) ? 'on' : 'off';
814
			}
815
			$errors[] = [
816
				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
817
				'hint' =>  $l->t('Adjusting this setting in php.ini will make ownCloud run again')
818
			];
819
			$webServerRestart = true;
820
		}
821
822
		/**
823
		 * The mbstring.func_overload check can only be performed if the mbstring
824
		 * module is installed as it will return null if the checking setting is
825
		 * not available and thus a check on the boolean value fails.
826
		 *
827
		 * TODO: Should probably be implemented in the above generic dependency
828
		 *       check somehow in the long-term.
829
		 */
830
		if($iniWrapper->getBool('mbstring.func_overload') !== null &&
831
			$iniWrapper->getBool('mbstring.func_overload') === true) {
832
			$errors[] = array(
833
				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
834
				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
835
			);
836
		}
837
838
		if(function_exists('xml_parser_create') &&
839
			version_compare('2.7.0', LIBXML_DOTTED_VERSION) === 1) {
840
			$errors[] = array(
841
				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [LIBXML_DOTTED_VERSION]),
842
				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
843
			);
844
		}
845
846
		if (!self::isAnnotationsWorking()) {
847
			$errors[] = array(
848
				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
849
				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
850
			);
851
		}
852
853
		if (!\OC::$CLI && $webServerRestart) {
854
			$errors[] = array(
855
				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
856
				'hint' => $l->t('Please ask your server administrator to restart the web server.')
857
			);
858
		}
859
860
		$errors = array_merge($errors, self::checkDatabaseVersion());
861
862
		// Cache the result of this function
863
		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
864
865
		return $errors;
866
	}
867
868
	/**
869
	 * Check the database version
870
	 *
871
	 * @return array errors array
872
	 */
873
	public static function checkDatabaseVersion() {
874
		$l = \OC::$server->getL10N('lib');
875
		$errors = array();
876
		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
877
		if ($dbType === 'pgsql') {
878
			// check PostgreSQL version
879
			try {
880
				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
881
				$data = $result->fetchRow();
882
				if (isset($data['server_version'])) {
883
					$version = $data['server_version'];
884
					if (version_compare($version, '9.0.0', '<')) {
885
						$errors[] = array(
886
							'error' => $l->t('PostgreSQL >= 9 required'),
887
							'hint' => $l->t('Please upgrade your database version')
888
						);
889
					}
890
				}
891
			} 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...
892
				$logger = \OC::$server->getLogger();
893
				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
894
				$logger->logException($e);
895
			}
896
		}
897
		return $errors;
898
	}
899
900
	/**
901
	 * Check for correct file permissions of data directory
902
	 *
903
	 * @param string $dataDirectory
904
	 * @return array arrays with error messages and hints
905
	 */
906
	public static function checkDataDirectoryPermissions($dataDirectory) {
907
		$l = \OC::$server->getL10N('lib');
908
		$errors = array();
909
		if (self::runningOnWindows()) {
910
			//TODO: permissions checks for windows hosts
911
		} else {
912
			$permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
913
				. ' cannot be listed by other users.');
914
			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
915
			if (substr($perms, -1) != '0') {
916
				chmod($dataDirectory, 0770);
917
				clearstatcache();
918
				$perms = substr(decoct(@fileperms($dataDirectory)), -3);
919 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...
920
					$errors[] = array(
921
						'error' => $l->t('Data directory (%s) is readable by other users', array($dataDirectory)),
922
						'hint' => $permissionsModHint
923
					);
924
				}
925
			}
926
		}
927
		return $errors;
928
	}
929
930
	/**
931
	 * Check that the data directory exists and is valid by
932
	 * checking the existence of the ".ocdata" file.
933
	 *
934
	 * @param string $dataDirectory data directory path
935
	 * @return array errors found
936
	 */
937
	public static function checkDataDirectoryValidity($dataDirectory) {
938
		$l = \OC::$server->getL10N('lib');
939
		$errors = [];
940 View Code Duplication
		if (!self::runningOnWindows() && $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...
941
			$errors[] = [
942
				'error' => $l->t('Data directory (%s) must be an absolute path', [$dataDirectory]),
943
				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
944
			];
945
		}
946 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...
947
			$errors[] = [
948
				'error' => $l->t('Data directory (%s) is invalid', [$dataDirectory]),
949
				'hint' => $l->t('Please check that the data directory contains a file' .
950
					' ".ocdata" in its root.')
951
			];
952
		}
953
		return $errors;
954
	}
955
956
	/**
957
	 * Check if the user is logged in, redirects to home if not. With
958
	 * redirect URL parameter to the request URI.
959
	 *
960
	 * @return void
961
	 */
962
	public static function checkLoggedIn() {
963
		// Check if we are a user
964
		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...
965
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php',
966
					[
967
						'redirect_url' => \OC::$server->getRequest()->getRequestUri()
968
					]
969
				)
970
			);
971
			exit();
972
		}
973
	}
974
975
	/**
976
	 * Check if the user is a admin, redirects to home if not
977
	 *
978
	 * @return void
979
	 */
980
	public static function checkAdminUser() {
981
		OC_Util::checkLoggedIn();
982
		if (!OC_User::isAdminUser(OC_User::getUser())) {
983
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
984
			exit();
985
		}
986
	}
987
988
	/**
989
	 * Check if it is allowed to remember login.
990
	 *
991
	 * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature
992
	 *
993
	 * @return bool
994
	 */
995
	public static function rememberLoginAllowed() {
996
997
		$apps = OC_App::getEnabledApps();
998
999
		foreach ($apps as $app) {
1000
			$appInfo = OC_App::getAppInfo($app);
1001
			if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') {
1002
				return false;
1003
			}
1004
1005
		}
1006
		return true;
1007
	}
1008
1009
	/**
1010
	 * Check if the user is a subadmin, redirects to home if not
1011
	 *
1012
	 * @return null|boolean $groups where the current user is subadmin
1013
	 */
1014
	public static function checkSubAdminUser() {
1015
		OC_Util::checkLoggedIn();
1016
		$userObject = \OC::$server->getUserSession()->getUser();
1017
		$isSubAdmin = false;
1018
		if($userObject !== null) {
1019
			$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1020
		}
1021
1022
		if (!$isSubAdmin) {
1023
			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1024
			exit();
1025
		}
1026
		return true;
1027
	}
1028
1029
	/**
1030
	 * Returns the URL of the default page
1031
	 * based on the system configuration and
1032
	 * the apps visible for the current user
1033
	 *
1034
	 * @return string URL
1035
	 */
1036
	public static function getDefaultPageUrl() {
1037
		$urlGenerator = \OC::$server->getURLGenerator();
1038
		// Deny the redirect if the URL contains a @
1039
		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
1040
		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1041
			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1042
		} else {
1043
			$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...
1044
			if ($defaultPage) {
1045
				$location = $urlGenerator->getAbsoluteURL($defaultPage);
1046
			} else {
1047
				$appId = 'files';
1048
				$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...
1049
				// find the first app that is enabled for the current user
1050
				foreach ($defaultApps as $defaultApp) {
1051
					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1052
					if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1053
						$appId = $defaultApp;
1054
						break;
1055
					}
1056
				}
1057
1058
				if(getenv('front_controller_active') === 'true') {
1059
					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1060
				} else {
1061
					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1062
				}
1063
			}
1064
		}
1065
		return $location;
1066
	}
1067
1068
	/**
1069
	 * Redirect to the user default page
1070
	 *
1071
	 * @return void
1072
	 */
1073
	public static function redirectToDefaultPage() {
1074
		$location = self::getDefaultPageUrl();
1075
		header('Location: ' . $location);
1076
		exit();
1077
	}
1078
1079
	/**
1080
	 * get an id unique for this instance
1081
	 *
1082
	 * @return string
1083
	 */
1084
	public static function getInstanceId() {
1085
		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1086
		if (is_null($id)) {
1087
			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1088
			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1089
			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1090
		}
1091
		return $id;
1092
	}
1093
1094
	/**
1095
	 * Public function to sanitize HTML
1096
	 *
1097
	 * This function is used to sanitize HTML and should be applied on any
1098
	 * string or array of strings before displaying it on a web page.
1099
	 *
1100
	 * @param string|array $value
1101
	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1102
	 */
1103
	public static function sanitizeHTML($value) {
1104
		if (is_array($value)) {
1105
			$value = array_map(function($value) {
1106
				return self::sanitizeHTML($value);
1107
			}, $value);
1108
		} else {
1109
			// Specify encoding for PHP<5.4
1110
			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1111
		}
1112
		return $value;
1113
	}
1114
1115
	/**
1116
	 * Public function to encode url parameters
1117
	 *
1118
	 * This function is used to encode path to file before output.
1119
	 * Encoding is done according to RFC 3986 with one exception:
1120
	 * Character '/' is preserved as is.
1121
	 *
1122
	 * @param string $component part of URI to encode
1123
	 * @return string
1124
	 */
1125
	public static function encodePath($component) {
1126
		$encoded = rawurlencode($component);
1127
		$encoded = str_replace('%2F', '/', $encoded);
1128
		return $encoded;
1129
	}
1130
1131
1132
	public function createHtaccessTestFile(\OCP\IConfig $config) {
1133
		// php dev server does not support htaccess
1134
		if (php_sapi_name() === 'cli-server') {
1135
			return false;
1136
		}
1137
1138
		// testdata
1139
		$fileName = '/htaccesstest.txt';
1140
		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1141
1142
		// creating a test file
1143
		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1144
1145
		if (file_exists($testFile)) {// already running this test, possible recursive call
1146
			return false;
1147
		}
1148
1149
		$fp = @fopen($testFile, 'w');
1150
		if (!$fp) {
1151
			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1152
				'Make sure it is possible for the webserver to write to ' . $testFile);
1153
		}
1154
		fwrite($fp, $testContent);
1155
		fclose($fp);
1156
	}
1157
1158
	/**
1159
	 * Check if the .htaccess file is working
1160
	 * @param \OCP\IConfig $config
1161
	 * @return bool
1162
	 * @throws Exception
1163
	 * @throws \OC\HintException If the test file can't get written.
1164
	 */
1165
	public function isHtaccessWorking(\OCP\IConfig $config) {
1166
1167
		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1168
			return true;
1169
		}
1170
1171
		$testContent = $this->createHtaccessTestFile($config);
1172
		if ($testContent === false) {
1173
			return false;
1174
		}
1175
1176
		$fileName = '/htaccesstest.txt';
1177
		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1178
1179
		// accessing the file via http
1180
		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1181
		try {
1182
			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1183
		} catch (\Exception $e) {
1184
			$content = false;
1185
		}
1186
1187
		// cleanup
1188
		@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...
1189
1190
		/*
1191
		 * If the content is not equal to test content our .htaccess
1192
		 * is working as required
1193
		 */
1194
		return $content !== $testContent;
1195
	}
1196
1197
	/**
1198
	 * Check if the setlocal call does not work. This can happen if the right
1199
	 * local packages are not available on the server.
1200
	 *
1201
	 * @return bool
1202
	 */
1203
	public static function isSetLocaleWorking() {
1204
		// setlocale test is pointless on Windows
1205
		if (OC_Util::runningOnWindows()) {
1206
			return true;
1207
		}
1208
1209
		\Patchwork\Utf8\Bootup::initLocale();
1210
		if ('' === basename('§')) {
1211
			return false;
1212
		}
1213
		return true;
1214
	}
1215
1216
	/**
1217
	 * Check if it's possible to get the inline annotations
1218
	 *
1219
	 * @return bool
1220
	 */
1221
	public static function isAnnotationsWorking() {
1222
		$reflection = new \ReflectionMethod(__METHOD__);
1223
		$docs = $reflection->getDocComment();
1224
1225
		return (is_string($docs) && strlen($docs) > 50);
1226
	}
1227
1228
	/**
1229
	 * Check if the PHP module fileinfo is loaded.
1230
	 *
1231
	 * @return bool
1232
	 */
1233
	public static function fileInfoLoaded() {
1234
		return function_exists('finfo_open');
1235
	}
1236
1237
	/**
1238
	 * clear all levels of output buffering
1239
	 *
1240
	 * @return void
1241
	 */
1242
	public static function obEnd() {
1243
		while (ob_get_level()) {
1244
			ob_end_clean();
1245
		}
1246
	}
1247
1248
	/**
1249
	 * Checks whether the server is running on Windows
1250
	 *
1251
	 * @return bool true if running on Windows, false otherwise
1252
	 */
1253
	public static function runningOnWindows() {
1254
		return (substr(PHP_OS, 0, 3) === "WIN");
1255
	}
1256
1257
	/**
1258
	 * Checks whether the server is running on Mac OS X
1259
	 *
1260
	 * @return bool true if running on Mac OS X, false otherwise
1261
	 */
1262
	public static function runningOnMac() {
1263
		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1264
	}
1265
1266
	/**
1267
	 * Checks whether server is running on HHVM
1268
	 *
1269
	 * @return bool True if running on HHVM, false otherwise
1270
	 */
1271
	public static function runningOnHhvm() {
1272
		return defined('HHVM_VERSION');
1273
	}
1274
1275
	/**
1276
	 * Handles the case that there may not be a theme, then check if a "default"
1277
	 * theme exists and take that one
1278
	 *
1279
	 * @return string the theme
1280
	 */
1281
	public static function getTheme() {
1282
		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1283
1284
		if ($theme === '') {
1285
			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1286
				$theme = 'default';
1287
			}
1288
		}
1289
1290
		return $theme;
1291
	}
1292
1293
	/**
1294
	 * Clear a single file from the opcode cache
1295
	 * This is useful for writing to the config file
1296
	 * in case the opcode cache does not re-validate files
1297
	 * Returns true if successful, false if unsuccessful:
1298
	 * caller should fall back on clearing the entire cache
1299
	 * with clearOpcodeCache() if unsuccessful
1300
	 *
1301
	 * @param string $path the path of the file to clear from the cache
1302
	 * @return bool true if underlying function returns true, otherwise false
1303
	 */
1304
	public static function deleteFromOpcodeCache($path) {
1305
		$ret = false;
1306
		if ($path) {
1307
			// APC >= 3.1.1
1308
			if (function_exists('apc_delete_file')) {
1309
				$ret = @apc_delete_file($path);
1310
			}
1311
			// Zend OpCache >= 7.0.0, PHP >= 5.5.0
1312
			if (function_exists('opcache_invalidate')) {
1313
				$ret = opcache_invalidate($path);
1314
			}
1315
		}
1316
		return $ret;
1317
	}
1318
1319
	/**
1320
	 * Clear the opcode cache if one exists
1321
	 * This is necessary for writing to the config file
1322
	 * in case the opcode cache does not re-validate files
1323
	 *
1324
	 * @return void
1325
	 */
1326
	public static function clearOpcodeCache() {
1327
		// APC
1328
		if (function_exists('apc_clear_cache')) {
1329
			apc_clear_cache();
1330
		}
1331
		// Zend Opcache
1332
		if (function_exists('accelerator_reset')) {
1333
			accelerator_reset();
1334
		}
1335
		// XCache
1336
		if (function_exists('xcache_clear_cache')) {
1337
			if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1338
				\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1339
			} else {
1340
				@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...
1341
			}
1342
		}
1343
		// Opcache (PHP >= 5.5)
1344
		if (function_exists('opcache_reset')) {
1345
			opcache_reset();
1346
		}
1347
	}
1348
1349
	/**
1350
	 * Normalize a unicode string
1351
	 *
1352
	 * @param string $value a not normalized string
1353
	 * @return bool|string
1354
	 */
1355
	public static function normalizeUnicode($value) {
1356
		if(Normalizer::isNormalized($value)) {
1357
			return $value;
1358
		}
1359
1360
		$normalizedValue = Normalizer::normalize($value);
1361
		if ($normalizedValue === null || $normalizedValue === false) {
1362
			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1363
			return $value;
1364
		}
1365
1366
		return $normalizedValue;
1367
	}
1368
1369
	/**
1370
	 * @param boolean|string $file
1371
	 * @return string
1372
	 */
1373
	public static function basename($file) {
1374
		$file = rtrim($file, '/');
1375
		$t = explode('/', $file);
1376
		return array_pop($t);
1377
	}
1378
1379
	/**
1380
	 * A human readable string is generated based on version, channel and build number
1381
	 *
1382
	 * @return string
1383
	 */
1384
	public static function getHumanVersion() {
1385
		$version = OC_Util::getVersionString() . ' (' . OC_Util::getChannel() . ')';
1386
		$build = OC_Util::getBuild();
1387
		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1388
			$version .= ' Build:' . $build;
1389
		}
1390
		return $version;
1391
	}
1392
1393
	/**
1394
	 * Returns whether the given file name is valid
1395
	 *
1396
	 * @param string $file file name to check
1397
	 * @return bool true if the file name is valid, false otherwise
1398
	 * @deprecated use \OC\Files\View::verifyPath()
1399
	 */
1400
	public static function isValidFileName($file) {
1401
		$trimmed = trim($file);
1402
		if ($trimmed === '') {
1403
			return false;
1404
		}
1405
		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1406
			return false;
1407
		}
1408
		foreach (str_split($trimmed) as $char) {
1409
			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1410
				return false;
1411
			}
1412
		}
1413
		return true;
1414
	}
1415
1416
	/**
1417
	 * Check whether the instance needs to perform an upgrade,
1418
	 * either when the core version is higher or any app requires
1419
	 * an upgrade.
1420
	 *
1421
	 * @param \OCP\IConfig $config
1422
	 * @return bool whether the core or any app needs an upgrade
1423
	 * @throws \OC\HintException When the upgrade from the given version is not allowed
1424
	 */
1425
	public static function needUpgrade(\OCP\IConfig $config) {
1426
		if ($config->getSystemValue('installed', false)) {
1427
			$installedVersion = $config->getSystemValue('version', '0.0.0');
1428
			$currentVersion = implode('.', \OCP\Util::getVersion());
1429
			$versionDiff = version_compare($currentVersion, $installedVersion);
1430
			if ($versionDiff > 0) {
1431
				return true;
1432
			} else if ($config->getSystemValue('debug', false) && $versionDiff < 0) {
1433
				// downgrade with debug
1434
				$installedMajor = explode('.', $installedVersion);
1435
				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1436
				$currentMajor = explode('.', $currentVersion);
1437
				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1438
				if ($installedMajor === $currentMajor) {
1439
					// Same major, allow downgrade for developers
1440
					return true;
1441
				} else {
1442
					// downgrade attempt, throw exception
1443
					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1444
				}
1445
			} else if ($versionDiff < 0) {
1446
				// downgrade attempt, throw exception
1447
				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1448
			}
1449
1450
			// also check for upgrades for apps (independently from the user)
1451
			$apps = \OC_App::getEnabledApps(false, true);
1452
			$shouldUpgrade = false;
1453
			foreach ($apps as $app) {
1454
				if (\OC_App::shouldUpgrade($app)) {
1455
					$shouldUpgrade = true;
1456
					break;
1457
				}
1458
			}
1459
			return $shouldUpgrade;
1460
		} else {
1461
			return false;
1462
		}
1463
	}
1464
1465
}
1466