Completed
Push — stable8 ( c45eda...dba072 )
by
unknown
15:55
created

OC_Util::getVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class for utility functions
5
 *
6
 */
7
class OC_Util {
8
	public static $scripts = array();
9
	public static $styles = array();
10
	public static $headers = array();
11
	private static $rootMounted = false;
12
	private static $fsSetup = false;
13
14
	private static function initLocalStorageRootFS() {
15
		// mount local file backend as root
16
		$configDataDirectory = OC_Config::getValue("datadirectory", OC::$SERVERROOT . "/data");
17
		//first set up the local "root" storage
18
		\OC\Files\Filesystem::initMounts();
19
		if (!self::$rootMounted) {
20
			\OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
21
			self::$rootMounted = true;
22
		}
23
	}
24
25
	/**
26
	 * mounting an object storage as the root fs will in essence remove the
27
	 * necessity of a data folder being present.
28
	 * TODO make home storage aware of this and use the object storage instead of local disk access
29
	 *
30
	 * @param array $config containing 'class' and optional 'arguments'
31
	 */
32
	private static function initObjectStoreRootFS($config) {
33
		// check misconfiguration
34
		if (empty($config['class'])) {
35
			\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
36
		}
37
		if (!isset($config['arguments'])) {
38
			$config['arguments'] = array();
39
		}
40
41
		// instantiate object store implementation
42
		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
43
		// mount with plain / root object store implementation
44
		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
45
46
		// mount object storage as root
47
		\OC\Files\Filesystem::initMounts();
48
		if (!self::$rootMounted) {
49
			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
50
			self::$rootMounted = true;
51
		}
52
	}
53
54
	/**
55
	 * Can be set up
56
	 *
57
	 * @param string $user
58
	 * @return boolean
59
	 * @description configure the initial filesystem based on the configuration
60
	 */
61
	public static function setupFS($user = '') {
62
		//setting up the filesystem twice can only lead to trouble
63
		if (self::$fsSetup) {
64
			return false;
65
		}
66
67
		\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
68
69
		// If we are not forced to load a specific user we load the one that is logged in
70
		if ($user == "" && OC_User::isLoggedIn()) {
71
			$user = OC_User::getUser();
72
		}
73
74
		// load all filesystem apps before, so no setup-hook gets lost
75
		OC_App::loadApps(array('filesystem'));
76
77
		// the filesystem will finish when $user is not empty,
78
		// mark fs setup here to avoid doing the setup from loading
79
		// OC_Filesystem
80
		if ($user != '') {
81
			self::$fsSetup = true;
82
		}
83
84
		//check if we are using an object storage
85
		$objectStore = OC_Config::getValue('objectstore');
86
		if (isset($objectStore)) {
87
			self::initObjectStoreRootFS($objectStore);
88
		} else {
89
			self::initLocalStorageRootFS();
90
		}
91
92
		if ($user != '' && !OCP\User::userExists($user)) {
93
			\OC::$server->getEventLogger()->end('setup_fs');
94
			return false;
95
		}
96
97
		//if we aren't logged in, there is no use to set up the filesystem
98
		if ($user != "") {
99
			\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
100
				// set up quota for home storages, even for other users
101
				// which can happen when using sharing
102
103
				/**
104
				 * @var \OC\Files\Storage\Storage $storage
105
				 */
106
				if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
107
					|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
108
				) {
109
					if (is_object($storage->getUser())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method getUser() does only exist in the following implementations of said interface: OC\Files\ObjectStore\HomeObjectStoreStorage, OC\Files\Storage\Home.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
110
						$user = $storage->getUser()->getUID();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method getUser() does only exist in the following implementations of said interface: OC\Files\ObjectStore\HomeObjectStoreStorage, OC\Files\Storage\Home.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
111
						$quota = OC_Util::getUserQuota($user);
112
						if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
113
							return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
114
						}
115
					}
116
				}
117
118
				return $storage;
119
			});
120
121
			$userDir = '/' . $user . '/files';
122
123
			//jail the user into his "home" directory
124
			\OC\Files\Filesystem::init($user, $userDir);
125
126
			$fileOperationProxy = new OC_FileProxy_FileOperations();
127
			OC_FileProxy::register($fileOperationProxy);
128
129
			//trigger creation of user home and /files folder
130
			\OC::$server->getUserFolder($user);
131
132
			OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
133
		}
134
		\OC::$server->getEventLogger()->end('setup_fs');
135
		return true;
136
	}
137
138
	/**
139
	 * check if a password is required for each public link
140
	 *
141
	 * @return boolean
142
	 */
143
	public static function isPublicLinkPasswordRequired() {
144
		$appConfig = \OC::$server->getAppConfig();
145
		$enforcePassword = $appConfig->getValue('core', 'shareapi_enforce_links_password', 'no');
146
		return ($enforcePassword === 'yes') ? true : false;
147
	}
148
149
	/**
150
	 * check if sharing is disabled for the current user
151
	 *
152
	 * @return boolean
153
	 */
154
	public static function isSharingDisabledForUser() {
155
		if (\OC_Appconfig::getValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
156
			$user = \OCP\User::getUser();
157
			$groupsList = \OC_Appconfig::getValue('core', 'shareapi_exclude_groups_list', '');
158
			$excludedGroups = explode(',', $groupsList);
159
			$usersGroups = \OC_Group::getUserGroups($user);
160
			if (!empty($usersGroups)) {
161
				$remainingGroups = array_diff($usersGroups, $excludedGroups);
162
				// if the user is only in groups which are disabled for sharing then
163
				// sharing is also disabled for the user
164
				if (empty($remainingGroups)) {
165
					return true;
166
				}
167
			}
168
		}
169
		return false;
170
	}
171
172
	/**
173
	 * check if share API enforces a default expire date
174
	 *
175
	 * @return boolean
176
	 */
177
	public static function isDefaultExpireDateEnforced() {
178
		$isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
179
		$enforceDefaultExpireDate = false;
180
		if ($isDefaultExpireDateEnabled === 'yes') {
181
			$value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
182
			$enforceDefaultExpireDate = ($value === 'yes') ? true : false;
183
		}
184
185
		return $enforceDefaultExpireDate;
186
	}
187
188
	/**
189
	 * Get the quota of a user
190
	 *
191
	 * @param string $user
192
	 * @return int Quota bytes
193
	 */
194
	public static function getUserQuota($user) {
195
		$config = \OC::$server->getConfig();
196
		$userQuota = $config->getUserValue($user, 'files', 'quota', 'default');
197
		if ($userQuota === 'default') {
198
			$userQuota = $config->getAppValue('files', 'default_quota', 'none');
199
		}
200
		if($userQuota === 'none') {
201
			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
202
		}else{
203
			return OC_Helper::computerFileSize($userQuota);
204
		}
205
	}
206
207
	/**
208
	 * copies the skeleton to the users /files
209
	 *
210
	 * @param \OC\User\User $user
211
	 * @param \OCP\Files\Folder $userDirectory
212
	 */
213
	public static function copySkeleton(\OC\User\User $user, \OCP\Files\Folder $userDirectory) {
214
215
		$skeletonDirectory = \OCP\Config::getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
216
217
		if (!empty($skeletonDirectory)) {
218
			\OCP\Util::writeLog(
219
				'files_skeleton',
220
				'copying skeleton for '.$user->getUID().' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
221
				\OCP\Util::DEBUG
222
			);
223
			self::copyr($skeletonDirectory, $userDirectory);
224
			// update the file cache
225
			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
226
		}
227
	}
228
229
	/**
230
	 * copies a directory recursively by using streams
231
	 *
232
	 * @param string $source
233
	 * @param \OCP\Files\Folder $target
234
	 * @return void
235
	 */
236
	public static function copyr($source, \OCP\Files\Folder $target) {
237
		$dir = opendir($source);
238
		while (false !== ($file = readdir($dir))) {
239
			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
240
				if (is_dir($source . '/' . $file)) {
241
					$child = $target->newFolder($file);
242
					self::copyr($source . '/' . $file, $child);
243
				} else {
244
					$child = $target->newFile($file);
245
					stream_copy_to_stream(fopen($source . '/' . $file,'r'), $child->fopen('w'));
246
				}
247
			}
248
		}
249
		closedir($dir);
250
	}
251
252
	/**
253
	 * @return void
254
	 */
255
	public static function tearDownFS() {
256
		\OC\Files\Filesystem::tearDown();
257
		self::$fsSetup = false;
258
		self::$rootMounted = false;
259
	}
260
261
	/**
262
	 * get the current installed version of ownCloud
263
	 *
264
	 * @return array
265
	 */
266
	public static function getVersion() {
267
		OC_Util::loadVersion();
268
		return \OC::$server->getSession()->get('OC_Version');
269
	}
270
271
	/**
272
	 * get the current installed version string of ownCloud
273
	 *
274
	 * @return string
275
	 */
276
	public static function getVersionString() {
277
		OC_Util::loadVersion();
278
		return \OC::$server->getSession()->get('OC_VersionString');
279
	}
280
281
	/**
282
	 * @description get the current installed edition of ownCloud. There is the community
283
	 * edition that just returns an empty string and the enterprise edition
284
	 * that returns "Enterprise".
285
	 * @return string
286
	 */
287
	public static function getEditionString() {
288
		if (OC_App::isEnabled('enterprise_key')) {
289
			return "Enterprise";
290
		} else {
291
			return "";
292
		}
293
294
	}
295
296
	/**
297
	 * @description get the update channel of the current installed of ownCloud.
298
	 * @return string
299
	 */
300
	public static function getChannel() {
301
		OC_Util::loadVersion();
302
		return \OC::$server->getSession()->get('OC_Channel');
303
	}
304
305
	/**
306
	 * @description get the build number of the current installed of ownCloud.
307
	 * @return string
308
	 */
309
	public static function getBuild() {
310
		OC_Util::loadVersion();
311
		return \OC::$server->getSession()->get('OC_Build');
312
	}
313
314
	/**
315
	 * @description load the version.php into the session as cache
316
	 */
317
	private static function loadVersion() {
318
		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
319
		if (!\OC::$server->getSession()->exists('OC_Version') or OC::$server->getSession()->get('OC_Version_Timestamp') != $timestamp) {
320
			require OC::$SERVERROOT . '/version.php';
321
			$session = \OC::$server->getSession();
322
			/** @var $timestamp int */
323
			$session->set('OC_Version_Timestamp', $timestamp);
324
			/** @var $OC_Version string */
325
			$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...
326
			/** @var $OC_VersionString string */
327
			$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...
328
			/** @var $OC_Channel string */
329
			$session->set('OC_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...
330
			/** @var $OC_Build string */
331
			$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...
332
		}
333
	}
334
335
	/**
336
	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
337
	 *
338
	 * @param string $application application to get the files from
339
	 * @param string $directory directory withing this application (css, js, vendor, etc)
340
	 * @param string $file the file inside of the above folder
341
	 * @return string the path
342
	 */
343
	private static function generatePath($application, $directory, $file) {
344
		if (is_null($file)) {
345
			$file = $application;
346
			$application = "";
347
		}
348
		if (!empty($application)) {
349
			return "$application/$directory/$file";
350
		} else {
351
			return "$directory/$file";
352
		}
353
	}
354
355
	/**
356
	 * add a javascript file
357
	 *
358
	 * @param string $application application id
359
	 * @param string|null $file filename
360
	 * @return void
361
	 */
362
	public static function addScript($application, $file = null) {
363
		$path = OC_Util::generatePath($application, 'js', $file);
364
		if (!in_array($path, self::$scripts)) {
365
			// core js files need separate handling
366
			if ($application !== 'core' && $file !== null) {
367
				self::addTranslations($application);
368
			}
369
			self::$scripts[] = $path;
370
		}
371
	}
372
373
	/**
374
	 * add a javascript file from the vendor sub folder
375
	 *
376
	 * @param string $application application id
377
	 * @param string|null $file filename
378
	 * @return void
379
	 */
380
	public static function addVendorScript($application, $file = null) {
381
		$path = OC_Util::generatePath($application, 'vendor', $file);
382
		if (!in_array($path, self::$scripts)) {
383
			self::$scripts[] = $path;
384
		}
385
	}
386
387
	/**
388
	 * add a translation JS file
389
	 *
390
	 * @param string $application application id
391
	 * @param string $languageCode language code, defaults to the current language
392
	 */
393
	public static function addTranslations($application, $languageCode = null) {
394
		if (is_null($languageCode)) {
395
			$l = new \OC_L10N($application);
396
			$languageCode = $l->getLanguageCode($application);
397
		}
398
		if (!empty($application)) {
399
			$path = "$application/l10n/$languageCode";
400
		} else {
401
			$path = "l10n/$languageCode";
402
		}
403
		if (!in_array($path, self::$scripts)) {
404
			self::$scripts[] = $path;
405
		}
406
	}
407
408
	/**
409
	 * add a css file
410
	 *
411
	 * @param string $application application id
412
	 * @param string|null $file filename
413
	 * @return void
414
	 */
415
	public static function addStyle($application, $file = null) {
416
		$path = OC_Util::generatePath($application, 'css', $file);
417
		if (!in_array($path, self::$styles)) {
418
			self::$styles[] = $path;
419
		}
420
	}
421
422
	/**
423
	 * add a css file from the vendor sub folder
424
	 *
425
	 * @param string $application application id
426
	 * @param string|null $file filename
427
	 * @return void
428
	 */
429
	public static function addVendorStyle($application, $file = null) {
430
		$path = OC_Util::generatePath($application, 'vendor', $file);
431
		if (!in_array($path, self::$styles)) {
432
			self::$styles[] = $path;
433
		}
434
	}
435
436
	/**
437
	 * Add a custom element to the header
438
	 * If $text is null then the element will be written as empty element.
439
	 * So use "" to get a closing tag.
440
	 * @param string $tag tag name of the element
441
	 * @param array $attributes array of attributes for the element
442
	 * @param string $text the text content for the element
443
	 */
444 View Code Duplication
	public static function addHeader($tag, $attributes, $text=null) {
445
		self::$headers[] = array(
446
			'tag' => $tag,
447
			'attributes' => $attributes,
448
			'text' => $text
449
		);
450
	}
451
452
	/**
453
	 * formats a timestamp in the "right" way
454
	 *
455
	 * @param int $timestamp
456
	 * @param bool $dateOnly option to omit time from the result
457
	 * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
458
	 * @return string timestamp
459
	 *
460
	 * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
461
	 */
462
	public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
463
		if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
464
			$timeZone = new \DateTimeZone($timeZone);
465
		}
466
467
		/** @var \OC\DateTimeFormatter $formatter */
468
		$formatter = \OC::$server->query('DateTimeFormatter');
469
		if ($dateOnly) {
470
			return $formatter->formatDate($timestamp, 'long', $timeZone);
471
		}
472
		return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
473
	}
474
475
	/**
476
	 * check if the current server configuration is suitable for ownCloud
477
	 *
478
	 * @param \OCP\IConfig $config
479
	 * @return array arrays with error messages and hints
480
	 */
481
	public static function checkServer(\OCP\IConfig $config) {
482
		$l = \OC::$server->getL10N('lib');
483
		$errors = array();
484
		$CONFIG_DATADIRECTORY = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data');
485
486
		if (!self::needUpgrade($config) && $config->getSystemValue('installed', false)) {
487
			// this check needs to be done every time
488
			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
489
		}
490
491
		// Assume that if checkServer() succeeded before in this session, then all is fine.
492
		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
493
			return $errors;
494
		}
495
496
		$webServerRestart = false;
497
		$setup = new OC_Setup($config);
498
		$availableDatabases = $setup->getSupportedDatabases();
499 View Code Duplication
		if (empty($availableDatabases)) {
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...
500
			$errors[] = array(
501
				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
502
				'hint' => '' //TODO: sane hint
503
			);
504
			$webServerRestart = true;
505
		}
506
507
		// Check if config folder is writable.
508
		if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
509
			$errors[] = array(
510
				'error' => $l->t('Cannot write into "config" directory'),
511
				'hint' => $l->t('This can usually be fixed by '
512
					. '%sgiving the webserver write access to the config directory%s.',
513
					array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
514
			);
515
		}
516
517
		// Check if there is a writable install folder.
518
		if ($config->getSystemValue('appstoreenabled', true)) {
519
			if (OC_App::getInstallPath() === null
520
				|| !is_writable(OC_App::getInstallPath())
521
				|| !is_readable(OC_App::getInstallPath())
522
			) {
523
				$errors[] = array(
524
					'error' => $l->t('Cannot write into "apps" directory'),
525
					'hint' => $l->t('This can usually be fixed by '
526
						. '%sgiving the webserver write access to the apps directory%s'
527
						. ' or disabling the appstore in the config file.',
528
						array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
529
				);
530
			}
531
		}
532
		// Create root dir.
533
		if ($config->getSystemValue('installed', false)) {
534
			if (!is_dir($CONFIG_DATADIRECTORY)) {
535
				$success = @mkdir($CONFIG_DATADIRECTORY);
536
				if ($success) {
537
					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
538
				} else {
539
					$errors[] = array(
540
						'error' => $l->t('Cannot create "data" directory (%s)', array($CONFIG_DATADIRECTORY)),
541
						'hint' => $l->t('This can usually be fixed by '
542
							. '<a href="%s" target="_blank">giving the webserver write access to the root directory</a>.',
543
							array(OC_Helper::linkToDocs('admin-dir_permissions')))
544
					);
545
				}
546
			} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
547
				//common hint for all file permissions error messages
548
				$permissionsHint = $l->t('Permissions can usually be fixed by '
549
					. '%sgiving the webserver write access to the root directory%s.',
550
					array('<a href="' . \OC_Helper::linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'));
551
				$errors[] = array(
552
					'error' => 'Data directory (' . $CONFIG_DATADIRECTORY . ') not writable by ownCloud',
553
					'hint' => $permissionsHint
554
				);
555
			} else {
556
				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
557
			}
558
		}
559
560
		if (!OC_Util::isSetLocaleWorking()) {
561
			$errors[] = array(
562
				'error' => $l->t('Setting locale to %s failed',
563
					array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
564
						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
565
				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
566
			);
567
		}
568
569
		// Contains the dependencies that should be checked against
570
		// classes = class_exists
571
		// functions = function_exists
572
		// defined = defined
573
		// If the dependency is not found the missing module name is shown to the EndUser
574
		$dependencies = array(
575
			'classes' => array(
576
				'ZipArchive' => 'zip',
577
				'DOMDocument' => 'dom',
578
				'XMLWriter' => 'XMLWriter'
579
			),
580
			'functions' => [
581
				'xml_parser_create' => 'libxml',
582
				'mb_detect_encoding' => 'mb multibyte',
583
				'ctype_digit' => 'ctype',
584
				'json_encode' => 'JSON',
585
				'gd_info' => 'GD',
586
				'gzencode' => 'zlib',
587
				'iconv' => 'iconv',
588
				'simplexml_load_string' => 'SimpleXML',
589
				'hash' => 'HASH Message Digest Framework',
590
			],
591
			'defined' => array(
592
				'PDO::ATTR_DRIVER_NAME' => 'PDO'
593
			)
594
		);
595
		$missingDependencies = array();
596
		$moduleHint = $l->t('Please ask your server administrator to install the module.');
597
598
		foreach ($dependencies['classes'] as $class => $module) {
599
			if (!class_exists($class)) {
600
				$missingDependencies[] = $module;
601
			}
602
		}
603
		foreach ($dependencies['functions'] as $function => $module) {
604
			if (!function_exists($function)) {
605
				$missingDependencies[] = $module;
606
			}
607
		}
608
		foreach ($dependencies['defined'] as $defined => $module) {
609
			if (!defined($defined)) {
610
				$missingDependencies[] = $module;
611
			}
612
		}
613
614
		foreach($missingDependencies as $missingDependency) {
615
			$errors[] = array(
616
				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
617
				'hint' => $moduleHint
618
			);
619
			$webServerRestart = true;
620
		}
621
622
		if (version_compare(phpversion(), '5.4.0', '<')) {
623
			$errors[] = array(
624
				'error' => $l->t('PHP %s or higher is required.', '5.4.0'),
0 ignored issues
show
Documentation introduced by
'5.4.0' is of type string, but the function expects a array.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
625
				'hint' => $l->t('Please ask your server administrator to update PHP to the latest version.'
626
					. ' Your PHP version is no longer supported by ownCloud and the PHP community.')
627
			);
628
			$webServerRestart = true;
629
		}
630
631
		if (!self::isAnnotationsWorking()) {
632
			$errors[] = array(
633
				'error' => $l->t('PHP is apparently setup to strip inline doc blocks. This will make several core apps inaccessible.'),
634
				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
635
			);
636
		}
637
638 View Code Duplication
		if ($webServerRestart) {
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...
639
			$errors[] = array(
640
				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
641
				'hint' => $l->t('Please ask your server administrator to restart the web server.')
642
			);
643
		}
644
645
		$errors = array_merge($errors, self::checkDatabaseVersion());
646
647
		// Cache the result of this function
648
		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
649
650
		return $errors;
651
	}
652
653
	/**
654
	 * Check the database version
655
	 *
656
	 * @return array errors array
657
	 */
658
	public static function checkDatabaseVersion() {
659
		$l = \OC::$server->getL10N('lib');
660
		$errors = array();
661
		$dbType = \OC_Config::getValue('dbtype', 'sqlite');
662
		if ($dbType === 'pgsql') {
663
			// check PostgreSQL version
664
			try {
665
				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
666
				$data = $result->fetchRow();
667
				if (isset($data['server_version'])) {
668
					$version = $data['server_version'];
669
					if (version_compare($version, '9.0.0', '<')) {
670
						$errors[] = array(
671
							'error' => $l->t('PostgreSQL >= 9 required'),
672
							'hint' => $l->t('Please upgrade your database version')
673
						);
674
					}
675
				}
676
			} 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...
677
				\OCP\Util::logException('core', $e);
678
				$errors[] = array(
679
					'error' => $l->t('Error occurred while checking PostgreSQL version'),
680
					'hint' => $l->t('Please make sure you have PostgreSQL >= 9 or'
681
						. ' check the logs for more information about the error')
682
				);
683
			}
684
		}
685
		return $errors;
686
	}
687
688
689
	/**
690
	 * check if there are still some encrypted files stored
691
	 *
692
	 * @return boolean
693
	 */
694 View Code Duplication
	public static function encryptedFiles() {
695
		//check if encryption was enabled in the past
696
		$encryptedFiles = false;
697
		if (OC_App::isEnabled('files_encryption') === false) {
698
			$view = new OC\Files\View('/' . OCP\User::getUser());
699
			$keysPath = '/files_encryption/keys';
700
			if ($view->is_dir($keysPath)) {
701
				$dircontent = $view->getDirectoryContent($keysPath);
702
				if (!empty($dircontent)) {
703
					$encryptedFiles = true;
704
				}
705
			}
706
		}
707
708
		return $encryptedFiles;
709
	}
710
711
	/**
712
	 * check if a backup from the encryption keys exists
713
	 *
714
	 * @return boolean
715
	 */
716 View Code Duplication
	public static function backupKeysExists() {
717
		//check if encryption was enabled in the past
718
		$backupExists = false;
719
		if (OC_App::isEnabled('files_encryption') === false) {
720
			$view = new OC\Files\View('/' . OCP\User::getUser());
721
			$backupPath = '/files_encryption/backup.decryptAll';
722
			if ($view->is_dir($backupPath)) {
723
				$dircontent = $view->getDirectoryContent($backupPath);
724
				if (!empty($dircontent)) {
725
					$backupExists = true;
726
				}
727
			}
728
		}
729
730
		return $backupExists;
731
	}
732
733
	/**
734
	 * Check for correct file permissions of data directory
735
	 *
736
	 * @param string $dataDirectory
737
	 * @return array arrays with error messages and hints
738
	 */
739
	public static function checkDataDirectoryPermissions($dataDirectory) {
740
		$l = \OC::$server->getL10N('lib');
741
		$errors = array();
742
		if (self::runningOnWindows()) {
743
			//TODO: permissions checks for windows hosts
744
		} else {
745
			$permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
746
				. ' cannot be listed by other users.');
747
			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
748
			if (substr($perms, -1) != '0') {
749
				chmod($dataDirectory, 0770);
750
				clearstatcache();
751
				$perms = substr(decoct(@fileperms($dataDirectory)), -3);
752 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...
753
					$errors[] = array(
754
						'error' => $l->t('Data directory (%s) is readable by other users', array($dataDirectory)),
755
						'hint' => $permissionsModHint
756
					);
757
				}
758
			}
759
		}
760
		return $errors;
761
	}
762
763
	/**
764
	 * Check that the data directory exists and is valid by
765
	 * checking the existence of the ".ocdata" file.
766
	 *
767
	 * @param string $dataDirectory data directory path
768
	 * @return bool true if the data directory is valid, false otherwise
769
	 */
770
	public static function checkDataDirectoryValidity($dataDirectory) {
771
		$l = \OC::$server->getL10N('lib');
772
		$errors = array();
773 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...
774
			$errors[] = array(
775
				'error' => $l->t('Data directory (%s) is invalid', array($dataDirectory)),
776
				'hint' => $l->t('Please check that the data directory contains a file' .
777
					' ".ocdata" in its root.')
778
			);
779
		}
780
		return $errors;
781
	}
782
783
	/**
784
	 * @param array $errors
785
	 * @param string[] $messages
786
	 */
787
	public static function displayLoginPage($errors = array(), $messages = []) {
788
		$parameters = array();
789
		foreach ($errors as $value) {
790
			$parameters[$value] = true;
791
		}
792
		$parameters['messages'] = $messages;
793
		if (!empty($_REQUEST['user'])) {
794
			$parameters["username"] = $_REQUEST['user'];
795
			$parameters['user_autofocus'] = false;
796
		} else {
797
			$parameters["username"] = '';
798
			$parameters['user_autofocus'] = true;
799
		}
800
		if (isset($_REQUEST['redirect_url'])) {
801
			$redirectUrl = $_REQUEST['redirect_url'];
802
			$parameters['redirect_url'] = urlencode($redirectUrl);
803
		}
804
805
		$parameters['alt_login'] = OC_App::getAlternativeLogIns();
806
		$parameters['rememberLoginAllowed'] = self::rememberLoginAllowed();
807
		OC_Template::printGuestPage("", "login", $parameters);
808
	}
809
810
811
	/**
812
	 * Check if the app is enabled, redirects to home if not
813
	 *
814
	 * @param string $app
815
	 * @return void
816
	 */
817
	public static function checkAppEnabled($app) {
818
		if (!OC_App::isEnabled($app)) {
819
			header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
820
			exit();
821
		}
822
	}
823
824
	/**
825
	 * Check if the user is logged in, redirects to home if not. With
826
	 * redirect URL parameter to the request URI.
827
	 *
828
	 * @return void
829
	 */
830
	public static function checkLoggedIn() {
831
		// Check if we are a user
832
		if (!OC_User::isLoggedIn()) {
833
			header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php',
834
					array('redirect_url' => OC_Request::requestUri())
835
				));
836
			exit();
837
		}
838
	}
839
840
	/**
841
	 * Check if the user is a admin, redirects to home if not
842
	 *
843
	 * @return void
844
	 */
845 View Code Duplication
	public static function checkAdminUser() {
846
		OC_Util::checkLoggedIn();
847
		if (!OC_User::isAdminUser(OC_User::getUser())) {
848
			header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
849
			exit();
850
		}
851
	}
852
853
	/**
854
	 * Check if it is allowed to remember login.
855
	 *
856
	 * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature
857
	 *
858
	 * @return bool
859
	 */
860
	public static function rememberLoginAllowed() {
861
862
		$apps = OC_App::getEnabledApps();
863
864
		foreach ($apps as $app) {
865
			$appInfo = OC_App::getAppInfo($app);
866
			if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') {
867
				return false;
868
			}
869
870
		}
871
		return true;
872
	}
873
874
	/**
875
	 * Check if the user is a subadmin, redirects to home if not
876
	 *
877
	 * @return null|boolean $groups where the current user is subadmin
878
	 */
879 View Code Duplication
	public static function checkSubAdminUser() {
880
		OC_Util::checkLoggedIn();
881
		if (!OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
882
			header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
883
			exit();
884
		}
885
		return true;
886
	}
887
888
	/**
889
	 * Returns the URL of the default page
890
	 * based on the system configuration and
891
	 * the apps visible for the current user
892
	 *
893
	 * @return string URL
894
	 */
895
	public static function getDefaultPageUrl() {
896
		$urlGenerator = \OC::$server->getURLGenerator();
897
		// Deny the redirect if the URL contains a @
898
		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
899
		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
900
			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
901
		} else {
902
			$defaultPage = OC_Appconfig::getValue('core', 'defaultpage');
903
			if ($defaultPage) {
904
				$location = $urlGenerator->getAbsoluteURL($defaultPage);
905
			} else {
906
				$appId = 'files';
907
				$defaultApps = explode(',', \OCP\Config::getSystemValue('defaultapp', 'files'));
908
				// find the first app that is enabled for the current user
909
				foreach ($defaultApps as $defaultApp) {
910
					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
911
					if (OC_App::isEnabled($defaultApp)) {
912
						$appId = $defaultApp;
913
						break;
914
					}
915
				}
916
				$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
917
			}
918
		}
919
		return $location;
920
	}
921
922
	/**
923
	 * Redirect to the user default page
924
	 *
925
	 * @return void
926
	 */
927
	public static function redirectToDefaultPage() {
928
		$location = self::getDefaultPageUrl();
929
		header('Location: ' . $location);
930
		exit();
931
	}
932
933
	/**
934
	 * get an id unique for this instance
935
	 *
936
	 * @return string
937
	 */
938
	public static function getInstanceId() {
939
		$id = OC_Config::getValue('instanceid', null);
940
		if (is_null($id)) {
941
			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
942
			$id = 'oc' . \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
943
			OC_Config::$object->setValue('instanceid', $id);
944
		}
945
		return $id;
946
	}
947
948
	/**
949
	 * Register an get/post call. Important to prevent CSRF attacks.
950
	 *
951
	 * @return string Generated token.
952
	 * @description
953
	 * Creates a 'request token' (random) and stores it inside the session.
954
	 * Ever subsequent (ajax) request must use such a valid token to succeed,
955
	 * otherwise the request will be denied as a protection against CSRF.
956
	 * @see OC_Util::isCallRegistered()
957
	 */
958
	public static function callRegister() {
959
		// Check if a token exists
960
		if (!\OC::$server->getSession()->exists('requesttoken')) {
961
			// No valid token found, generate a new one.
962
			$requestToken = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(30);
963
			\OC::$server->getSession()->set('requesttoken', $requestToken);
964
		} else {
965
			// Valid token already exists, send it
966
			$requestToken = \OC::$server->getSession()->get('requesttoken');
967
		}
968
		return ($requestToken);
969
	}
970
971
	/**
972
	 * Check an ajax get/post call if the request token is valid.
973
	 *
974
	 * @return boolean False if request token is not set or is invalid.
975
	 * @see OC_Util::callRegister()
976
	 */
977
	public static function isCallRegistered() {
978
		return \OC::$server->getRequest()->passesCSRFCheck();
979
	}
980
981
	/**
982
	 * Check an ajax get/post call if the request token is valid. Exit if not.
983
	 *
984
	 * @return void
985
	 */
986
	public static function callCheck() {
987
		if (!OC_Util::isCallRegistered()) {
988
			exit();
989
		}
990
	}
991
992
	/**
993
	 * Public function to sanitize HTML
994
	 *
995
	 * This function is used to sanitize HTML and should be applied on any
996
	 * string or array of strings before displaying it on a web page.
997
	 *
998
	 * @param string|array &$value
999
	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1000
	 */
1001
	public static function sanitizeHTML(&$value) {
1002
		if (is_array($value)) {
1003
			array_walk_recursive($value, 'OC_Util::sanitizeHTML');
1004
		} else {
1005
			//Specify encoding for PHP<5.4
1006
			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1007
		}
1008
		return $value;
1009
	}
1010
1011
	/**
1012
	 * Public function to encode url parameters
1013
	 *
1014
	 * This function is used to encode path to file before output.
1015
	 * Encoding is done according to RFC 3986 with one exception:
1016
	 * Character '/' is preserved as is.
1017
	 *
1018
	 * @param string $component part of URI to encode
1019
	 * @return string
1020
	 */
1021
	public static function encodePath($component) {
1022
		$encoded = rawurlencode($component);
1023
		$encoded = str_replace('%2F', '/', $encoded);
1024
		return $encoded;
1025
	}
1026
1027
	/**
1028
	 * Check if the .htaccess file is working
1029
	 *
1030
	 * @throws OC\HintException If the testfile can't get written.
1031
	 * @return bool
1032
	 * @description Check if the .htaccess file is working by creating a test
1033
	 * file in the data directory and trying to access via http
1034
	 */
1035
	public static function isHtaccessWorking() {
1036
		if (\OC::$CLI || !OC::$server->getConfig()->getSystemValue('check_for_working_htaccess', true)) {
1037
			return true;
1038
		}
1039
1040
		// php dev server does not support htaccess
1041
		if (php_sapi_name() === 'cli-server') {
1042
			return false;
1043
		}
1044
1045
		// testdata
1046
		$fileName = '/htaccesstest.txt';
1047
		$testContent = 'testcontent';
1048
1049
		// creating a test file
1050
		$testFile = OC::$server->getConfig()->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1051
1052
		if (file_exists($testFile)) {// already running this test, possible recursive call
1053
			return false;
1054
		}
1055
1056
		$fp = @fopen($testFile, 'w');
1057
		if (!$fp) {
1058
			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1059
				'Make sure it is possible for the webserver to write to ' . $testFile);
1060
		}
1061
		fwrite($fp, $testContent);
1062
		fclose($fp);
1063
1064
		// accessing the file via http
1065
		$url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName);
1066
		$content = self::getUrlContent($url);
1067
1068
		// cleanup
1069
		@unlink($testFile);
1070
1071
		/*
1072
		 * If the content is not equal to test content our .htaccess
1073
		 * is working as required
1074
		 */
1075
		return $content !== $testContent;
1076
	}
1077
1078
	/**
1079
	 * Check if the setlocal call does not work. This can happen if the right
1080
	 * local packages are not available on the server.
1081
	 *
1082
	 * @return bool
1083
	 */
1084
	public static function isSetLocaleWorking() {
1085
		// setlocale test is pointless on Windows
1086
		if (OC_Util::runningOnWindows()) {
1087
			return true;
1088
		}
1089
1090
		\Patchwork\Utf8\Bootup::initLocale();
1091
		if ('' === basename('§')) {
1092
			return false;
1093
		}
1094
		return true;
1095
	}
1096
1097
	/**
1098
	 * Check if it's possible to get the inline annotations
1099
	 *
1100
	 * @return bool
1101
	 */
1102
	public static function isAnnotationsWorking() {
1103
		$reflection = new \ReflectionMethod(__METHOD__);
1104
		$docs = $reflection->getDocComment();
1105
1106
		return (is_string($docs) && strlen($docs) > 50);
1107
	}
1108
1109
	/**
1110
	 * Check if the PHP module fileinfo is loaded.
1111
	 *
1112
	 * @return bool
1113
	 */
1114
	public static function fileInfoLoaded() {
1115
		return function_exists('finfo_open');
1116
	}
1117
1118
	/**
1119
	 * Check if the ownCloud server can connect to the internet
1120
	 *
1121
	 * @return bool
1122
	 */
1123
	public static function isInternetConnectionWorking() {
1124
		// in case there is no internet connection on purpose return false
1125
		if (self::isInternetConnectionEnabled() === false) {
1126
			return false;
1127
		}
1128
1129
		// in case the connection is via proxy return true to avoid connecting to owncloud.org
1130
		if (OC_Config::getValue('proxy', '') != '') {
1131
			return true;
1132
		}
1133
1134
		// try to connect to owncloud.org to see if http connections to the internet are possible.
1135
		$connected = @fsockopen("www.owncloud.org", 80);
1136
		if ($connected) {
1137
			fclose($connected);
1138
			return true;
1139
		} else {
1140
			// second try in case one server is down
1141
			$connected = @fsockopen("apps.owncloud.com", 80);
1142
			if ($connected) {
1143
				fclose($connected);
1144
				return true;
1145
			} else {
1146
				return false;
1147
			}
1148
		}
1149
	}
1150
1151
	/**
1152
	 * Check if the connection to the internet is disabled on purpose
1153
	 *
1154
	 * @return string
1155
	 */
1156
	public static function isInternetConnectionEnabled() {
1157
		return \OC_Config::getValue("has_internet_connection", true);
1158
	}
1159
1160
	/**
1161
	 * clear all levels of output buffering
1162
	 *
1163
	 * @return void
1164
	 */
1165
	public static function obEnd() {
1166
		while (ob_get_level()) {
1167
			ob_end_clean();
1168
		}
1169
	}
1170
1171
1172
	/**
1173
	 * Generates a cryptographic secure pseudo-random string
1174
	 *
1175
	 * @param int $length of the random string
1176
	 * @return string
1177
	 * @deprecated Use \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length); instead
1178
	 */
1179
	public static function generateRandomBytes($length = 30) {
1180
		return \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1181
	}
1182
1183
	/**
1184
	 * Checks if a secure random number generator is available
1185
	 *
1186
	 * @return true
1187
	 * @deprecated Function will be removed in the future and does only return true.
1188
	 */
1189
	public static function secureRNGAvailable() {
1190
		return true;
1191
	}
1192
1193
	/**
1194
	 * Get URL content
1195
	 * @param string $url Url to get content
1196
	 * @deprecated Use \OC::$server->getHTTPHelper()->getUrlContent($url);
1197
	 * @throws Exception If the URL does not start with http:// or https://
1198
	 * @return string of the response or false on error
1199
	 * This function get the content of a page via curl, if curl is enabled.
1200
	 * If not, file_get_contents is used.
1201
	 */
1202
	public static function getUrlContent($url) {
1203
		try {
1204
			return \OC::$server->getHTTPHelper()->getUrlContent($url);
1205
		} catch (\Exception $e) {
1206
			throw $e;
1207
		}
1208
	}
1209
1210
	/**
1211
	 * Checks whether the server is running on Windows
1212
	 *
1213
	 * @return bool true if running on Windows, false otherwise
1214
	 */
1215
	public static function runningOnWindows() {
1216
		return (substr(PHP_OS, 0, 3) === "WIN");
1217
	}
1218
1219
	/**
1220
	 * Checks whether the server is running on Mac OS X
1221
	 *
1222
	 * @return bool true if running on Mac OS X, false otherwise
1223
	 */
1224
	public static function runningOnMac() {
1225
		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1226
	}
1227
1228
	/**
1229
	 * Checks whether server is running on HHVM
1230
	 *
1231
	 * @return bool True if running on HHVM, false otherwise
1232
	 */
1233
	public static function runningOnHhvm() {
1234
		return defined('HHVM_VERSION');
1235
	}
1236
1237
	/**
1238
	 * Handles the case that there may not be a theme, then check if a "default"
1239
	 * theme exists and take that one
1240
	 *
1241
	 * @return string the theme
1242
	 */
1243
	public static function getTheme() {
1244
		$theme = OC_Config::getValue("theme", '');
1245
1246
		if ($theme === '') {
1247
			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1248
				$theme = 'default';
1249
			}
1250
		}
1251
1252
		return $theme;
1253
	}
1254
1255
	/**
1256
	 * Clear the opcode cache if one exists
1257
	 * This is necessary for writing to the config file
1258
	 * in case the opcode cache does not re-validate files
1259
	 *
1260
	 * @return void
1261
	 */
1262
	public static function clearOpcodeCache() {
1263
		// APC
1264
		if (function_exists('apc_clear_cache')) {
1265
			apc_clear_cache();
1266
		}
1267
		// Zend Opcache
1268
		if (function_exists('accelerator_reset')) {
1269
			accelerator_reset();
1270
		}
1271
		// XCache
1272
		if (function_exists('xcache_clear_cache')) {
1273
			if (ini_get('xcache.admin.enable_auth')) {
1274
				OC_Log::write('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OC_Log::WARN);
1275
			} else {
1276
				xcache_clear_cache(XC_TYPE_PHP, 0);
1277
			}
1278
		}
1279
		// Opcache (PHP >= 5.5)
1280
		if (function_exists('opcache_reset')) {
1281
			opcache_reset();
1282
		}
1283
	}
1284
1285
	/**
1286
	 * Normalize a unicode string
1287
	 *
1288
	 * @param string $value a not normalized string
1289
	 * @return bool|string
1290
	 */
1291
	public static function normalizeUnicode($value) {
1292
		if(Normalizer::isNormalized($value)) {
1293
			return $value;
1294
		}
1295
1296
		$normalizedValue = Normalizer::normalize($value);
1297
		if ($normalizedValue === null || $normalizedValue === false) {
1298
			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1299
			return $value;
1300
		}
1301
1302
		return $normalizedValue;
1303
	}
1304
1305
	/**
1306
	 * @param boolean|string $file
1307
	 * @return string
1308
	 */
1309
	public static function basename($file) {
1310
		$file = rtrim($file, '/');
1311
		$t = explode('/', $file);
1312
		return array_pop($t);
1313
	}
1314
1315
	/**
1316
	 * A human readable string is generated based on version, channel and build number
1317
	 *
1318
	 * @return string
1319
	 */
1320
	public static function getHumanVersion() {
1321
		$version = OC_Util::getVersionString() . ' (' . OC_Util::getChannel() . ')';
1322
		$build = OC_Util::getBuild();
1323
		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1324
			$version .= ' Build:' . $build;
1325
		}
1326
		return $version;
1327
	}
1328
1329
	/**
1330
	 * Returns whether the given file name is valid
1331
	 *
1332
	 * @param string $file file name to check
1333
	 * @return bool true if the file name is valid, false otherwise
1334
	 */
1335
	public static function isValidFileName($file) {
1336
		$trimmed = trim($file);
1337
		if ($trimmed === '') {
1338
			return false;
1339
		}
1340
		if ($trimmed === '.' || $trimmed === '..') {
1341
			return false;
1342
		}
1343
		foreach (str_split($trimmed) as $char) {
1344
			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1345
				return false;
1346
			}
1347
		}
1348
		return true;
1349
	}
1350
1351
	/**
1352
	 * Check whether the instance needs to perform an upgrade,
1353
	 * either when the core version is higher or any app requires
1354
	 * an upgrade.
1355
	 *
1356
	 * @param \OCP\IConfig $config
1357
	 * @return bool whether the core or any app needs an upgrade
1358
	 */
1359
	public static function needUpgrade(\OCP\IConfig $config) {
1360
		if ($config->getSystemValue('installed', false)) {
1361
			$installedVersion = $config->getSystemValue('version', '0.0.0');
1362
			$currentVersion = implode('.', OC_Util::getVersion());
1363
			if (version_compare($currentVersion, $installedVersion, '>')) {
1364
				return true;
1365
			}
1366
1367
			// also check for upgrades for apps (independently from the user)
1368
			$apps = \OC_App::getEnabledApps(false, true);
1369
			$shouldUpgrade = false;
1370
			foreach ($apps as $app) {
1371
				if (\OC_App::shouldUpgrade($app)) {
1372
					$shouldUpgrade = true;
1373
					break;
1374
				}
1375
			}
1376
			return $shouldUpgrade;
1377
		} else {
1378
			return false;
1379
		}
1380
	}
1381
1382
	/**
1383
	 * Check if PhpCharset config is UTF-8
1384
	 *
1385
	 * @return string
1386
	 */
1387
	public static function isPhpCharSetUtf8() {
1388
		return strtoupper(ini_get('default_charset')) === 'UTF-8';
1389
	}
1390
1391
}
1392