Completed
Push — master ( c93919...f057a2 )
by Robin
31:21 queued 16s
created
lib/private/legacy/OC_Util.php 2 patches
Indentation   +835 added lines, -835 removed lines patch added patch discarded remove patch
@@ -22,839 +22,839 @@
 block discarded – undo
22 22
  * @deprecated 32.0.0 Use \OCP\Util or any appropriate official API instead
23 23
  */
24 24
 class OC_Util {
25
-	public static $styles = [];
26
-	public static $headers = [];
27
-
28
-	/**
29
-	 * Setup the file system
30
-	 *
31
-	 * @param string|null $user
32
-	 * @return boolean
33
-	 * @description configure the initial filesystem based on the configuration
34
-	 * @suppress PhanDeprecatedFunction
35
-	 * @suppress PhanAccessMethodInternal
36
-	 */
37
-	public static function setupFS(?string $user = '') {
38
-		// If we are not forced to load a specific user we load the one that is logged in
39
-		if ($user === '') {
40
-			$userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
41
-		} else {
42
-			$userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
43
-		}
44
-
45
-		/** @var SetupManager $setupManager */
46
-		$setupManager = \OC::$server->get(SetupManager::class);
47
-
48
-		if ($userObject) {
49
-			$setupManager->setupForUser($userObject);
50
-		} else {
51
-			$setupManager->setupRoot();
52
-		}
53
-		return true;
54
-	}
55
-
56
-	/**
57
-	 * Check if a password is required for each public link
58
-	 *
59
-	 * @param bool $checkGroupMembership Check group membership exclusion
60
-	 * @return bool
61
-	 * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkEnforcePassword directly
62
-	 */
63
-	public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
64
-		/** @var IManager $shareManager */
65
-		$shareManager = \OC::$server->get(IManager::class);
66
-		return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
67
-	}
68
-
69
-	/**
70
-	 * check if sharing is disabled for the current user
71
-	 * @param IConfig $config
72
-	 * @param IGroupManager $groupManager
73
-	 * @param IUser|null $user
74
-	 * @return bool
75
-	 * @deprecated 32.0.0 use OCP\Share\IManager's sharingDisabledForUser directly
76
-	 */
77
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
78
-		/** @var IManager $shareManager */
79
-		$shareManager = \OC::$server->get(IManager::class);
80
-		$userId = $user ? $user->getUID() : null;
81
-		return $shareManager->sharingDisabledForUser($userId);
82
-	}
83
-
84
-	/**
85
-	 * check if share API enforces a default expire date
86
-	 *
87
-	 * @return bool
88
-	 * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkDefaultExpireDateEnforced directly
89
-	 */
90
-	public static function isDefaultExpireDateEnforced() {
91
-		/** @var IManager $shareManager */
92
-		$shareManager = \OC::$server->get(IManager::class);
93
-		return $shareManager->shareApiLinkDefaultExpireDateEnforced();
94
-	}
95
-
96
-	/**
97
-	 * Get the quota of a user
98
-	 *
99
-	 * @param IUser|null $user
100
-	 * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
101
-	 * @deprecated 9.0.0 - Use \OCP\IUser::getQuota or \OCP\IUser::getQuotaBytes
102
-	 */
103
-	public static function getUserQuota(?IUser $user) {
104
-		if (is_null($user)) {
105
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
106
-		}
107
-		$userQuota = $user->getQuota();
108
-		if ($userQuota === 'none') {
109
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
110
-		}
111
-		return \OCP\Util::computerFileSize($userQuota);
112
-	}
113
-
114
-	/**
115
-	 * copies the skeleton to the users /files
116
-	 *
117
-	 * @param string $userId
118
-	 * @param \OCP\Files\Folder $userDirectory
119
-	 * @throws \OCP\Files\NotFoundException
120
-	 * @throws \OCP\Files\NotPermittedException
121
-	 * @suppress PhanDeprecatedFunction
122
-	 */
123
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
124
-		/** @var LoggerInterface $logger */
125
-		$logger = \OC::$server->get(LoggerInterface::class);
126
-
127
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
128
-		$userLang = \OC::$server->get(IFactory::class)->findLanguage();
129
-		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
130
-
131
-		if (!file_exists($skeletonDirectory)) {
132
-			$dialectStart = strpos($userLang, '_');
133
-			if ($dialectStart !== false) {
134
-				$skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
135
-			}
136
-			if ($dialectStart === false || !file_exists($skeletonDirectory)) {
137
-				$skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
138
-			}
139
-			if (!file_exists($skeletonDirectory)) {
140
-				$skeletonDirectory = '';
141
-			}
142
-		}
143
-
144
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
145
-
146
-		if ($instanceId === null) {
147
-			throw new \RuntimeException('no instance id!');
148
-		}
149
-		$appdata = 'appdata_' . $instanceId;
150
-		if ($userId === $appdata) {
151
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
152
-		}
153
-
154
-		if (!empty($skeletonDirectory)) {
155
-			$logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
156
-			self::copyr($skeletonDirectory, $userDirectory);
157
-			// update the file cache
158
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
159
-
160
-			/** @var ITemplateManager $templateManager */
161
-			$templateManager = \OC::$server->get(ITemplateManager::class);
162
-			$templateManager->initializeTemplateDirectory(null, $userId);
163
-		}
164
-	}
165
-
166
-	/**
167
-	 * copies a directory recursively by using streams
168
-	 *
169
-	 * @param string $source
170
-	 * @param \OCP\Files\Folder $target
171
-	 * @return void
172
-	 */
173
-	public static function copyr($source, \OCP\Files\Folder $target) {
174
-		$logger = \OCP\Server::get(LoggerInterface::class);
175
-
176
-		// Verify if folder exists
177
-		$dir = opendir($source);
178
-		if ($dir === false) {
179
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
180
-			return;
181
-		}
182
-
183
-		// Copy the files
184
-		while (false !== ($file = readdir($dir))) {
185
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
186
-				if (is_dir($source . '/' . $file)) {
187
-					$child = $target->newFolder($file);
188
-					self::copyr($source . '/' . $file, $child);
189
-				} else {
190
-					$sourceStream = fopen($source . '/' . $file, 'r');
191
-					if ($sourceStream === false) {
192
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
193
-						closedir($dir);
194
-						return;
195
-					}
196
-					$target->newFile($file, $sourceStream);
197
-				}
198
-			}
199
-		}
200
-		closedir($dir);
201
-	}
202
-
203
-	/**
204
-	 * @deprecated 32.0.0 Call tearDown directly on SetupManager
205
-	 */
206
-	public static function tearDownFS(): void {
207
-		$setupManager = \OCP\Server::get(SetupManager::class);
208
-		$setupManager->tearDown();
209
-	}
210
-
211
-	/**
212
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
213
-	 *
214
-	 * @param string $application application to get the files from
215
-	 * @param string $directory directory within this application (css, js, vendor, etc)
216
-	 * @param ?string $file the file inside of the above folder
217
-	 */
218
-	private static function generatePath($application, $directory, $file): string {
219
-		if (is_null($file)) {
220
-			$file = $application;
221
-			$application = '';
222
-		}
223
-		if (!empty($application)) {
224
-			return "$application/$directory/$file";
225
-		} else {
226
-			return "$directory/$file";
227
-		}
228
-	}
229
-
230
-	/**
231
-	 * add a css file
232
-	 *
233
-	 * @param string $application application id
234
-	 * @param string|null $file filename
235
-	 * @param bool $prepend prepend the Style to the beginning of the list
236
-	 * @deprecated 32.0.0 Use \OCP\Util::addStyle
237
-	 */
238
-	public static function addStyle($application, $file = null, $prepend = false): void {
239
-		$path = OC_Util::generatePath($application, 'css', $file);
240
-		self::addExternalResource($application, $prepend, $path, 'style');
241
-	}
242
-
243
-	/**
244
-	 * add a css file from the vendor sub folder
245
-	 *
246
-	 * @param string $application application id
247
-	 * @param string|null $file filename
248
-	 * @param bool $prepend prepend the Style to the beginning of the list
249
-	 * @deprecated 32.0.0
250
-	 */
251
-	public static function addVendorStyle($application, $file = null, $prepend = false): void {
252
-		$path = OC_Util::generatePath($application, 'vendor', $file);
253
-		self::addExternalResource($application, $prepend, $path, 'style');
254
-	}
255
-
256
-	/**
257
-	 * add an external resource css/js file
258
-	 *
259
-	 * @param string $application application id
260
-	 * @param bool $prepend prepend the file to the beginning of the list
261
-	 * @param string $path
262
-	 * @param string $type (script or style)
263
-	 */
264
-	private static function addExternalResource($application, $prepend, $path, $type = 'script'): void {
265
-		if ($type === 'style') {
266
-			if (!in_array($path, self::$styles)) {
267
-				if ($prepend === true) {
268
-					array_unshift(self::$styles, $path);
269
-				} else {
270
-					self::$styles[] = $path;
271
-				}
272
-			}
273
-		}
274
-	}
275
-
276
-	/**
277
-	 * Add a custom element to the header
278
-	 * If $text is null then the element will be written as empty element.
279
-	 * So use "" to get a closing tag.
280
-	 * @param string $tag tag name of the element
281
-	 * @param array $attributes array of attributes for the element
282
-	 * @param string $text the text content for the element
283
-	 * @param bool $prepend prepend the header to the beginning of the list
284
-	 * @deprecated 32.0.0 Use \OCP\Util::addHeader instead
285
-	 */
286
-	public static function addHeader($tag, $attributes, $text = null, $prepend = false): void {
287
-		$header = [
288
-			'tag' => $tag,
289
-			'attributes' => $attributes,
290
-			'text' => $text
291
-		];
292
-		if ($prepend === true) {
293
-			array_unshift(self::$headers, $header);
294
-		} else {
295
-			self::$headers[] = $header;
296
-		}
297
-	}
298
-
299
-	/**
300
-	 * check if the current server configuration is suitable for ownCloud
301
-	 *
302
-	 * @return array arrays with error messages and hints
303
-	 */
304
-	public static function checkServer(\OC\SystemConfig $config) {
305
-		$l = \OC::$server->getL10N('lib');
306
-		$errors = [];
307
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
308
-
309
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
310
-			// this check needs to be done every time
311
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
312
-		}
313
-
314
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
315
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
316
-			return $errors;
317
-		}
318
-
319
-		$webServerRestart = false;
320
-		$setup = \OCP\Server::get(\OC\Setup::class);
321
-
322
-		$urlGenerator = \OC::$server->getURLGenerator();
323
-
324
-		$availableDatabases = $setup->getSupportedDatabases();
325
-		if (empty($availableDatabases)) {
326
-			$errors[] = [
327
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
328
-				'hint' => '' //TODO: sane hint
329
-			];
330
-			$webServerRestart = true;
331
-		}
332
-
333
-		// Check if config folder is writable.
334
-		if (!(bool)$config->getValue('config_is_read_only', false)) {
335
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
336
-				$errors[] = [
337
-					'error' => $l->t('Cannot write into "config" directory.'),
338
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
339
-						[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
340
-						. $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
341
-							[ $urlGenerator->linkToDocs('admin-config') ])
342
-				];
343
-			}
344
-		}
345
-
346
-		// Check if there is a writable install folder.
347
-		if ($config->getValue('appstoreenabled', true)) {
348
-			if (OC_App::getInstallPath() === null
349
-				|| !is_writable(OC_App::getInstallPath())
350
-				|| !is_readable(OC_App::getInstallPath())
351
-			) {
352
-				$errors[] = [
353
-					'error' => $l->t('Cannot write into "apps" directory.'),
354
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
355
-						. ' or disabling the App Store in the config file.')
356
-				];
357
-			}
358
-		}
359
-		// Create root dir.
360
-		if ($config->getValue('installed', false)) {
361
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
362
-				$success = @mkdir($CONFIG_DATADIRECTORY);
363
-				if ($success) {
364
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
365
-				} else {
366
-					$errors[] = [
367
-						'error' => $l->t('Cannot create "data" directory.'),
368
-						'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
369
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
370
-					];
371
-				}
372
-			} elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
373
-				// is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
374
-				$testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
375
-				$handle = fopen($testFile, 'w');
376
-				if (!$handle || fwrite($handle, 'Test write operation') === false) {
377
-					$permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
378
-						[$urlGenerator->linkToDocs('admin-dir_permissions')]);
379
-					$errors[] = [
380
-						'error' => $l->t('Your data directory is not writable.'),
381
-						'hint' => $permissionsHint
382
-					];
383
-				} else {
384
-					fclose($handle);
385
-					unlink($testFile);
386
-				}
387
-			} else {
388
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
389
-			}
390
-		}
391
-
392
-		if (!OC_Util::isSetLocaleWorking()) {
393
-			$errors[] = [
394
-				'error' => $l->t('Setting locale to %s failed.',
395
-					['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
396
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
397
-				'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
398
-			];
399
-		}
400
-
401
-		// Contains the dependencies that should be checked against
402
-		// classes = class_exists
403
-		// functions = function_exists
404
-		// defined = defined
405
-		// ini = ini_get
406
-		// If the dependency is not found the missing module name is shown to the EndUser
407
-		// When adding new checks always verify that they pass on CI as well
408
-		$dependencies = [
409
-			'classes' => [
410
-				'ZipArchive' => 'zip',
411
-				'DOMDocument' => 'dom',
412
-				'XMLWriter' => 'XMLWriter',
413
-				'XMLReader' => 'XMLReader',
414
-			],
415
-			'functions' => [
416
-				'xml_parser_create' => 'libxml',
417
-				'mb_strcut' => 'mbstring',
418
-				'ctype_digit' => 'ctype',
419
-				'json_encode' => 'JSON',
420
-				'gd_info' => 'GD',
421
-				'gzencode' => 'zlib',
422
-				'simplexml_load_string' => 'SimpleXML',
423
-				'hash' => 'HASH Message Digest Framework',
424
-				'curl_init' => 'cURL',
425
-				'openssl_verify' => 'OpenSSL',
426
-			],
427
-			'defined' => [
428
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
429
-			],
430
-			'ini' => [
431
-				'default_charset' => 'UTF-8',
432
-			],
433
-		];
434
-		$missingDependencies = [];
435
-		$invalidIniSettings = [];
436
-
437
-		$iniWrapper = \OC::$server->get(IniGetWrapper::class);
438
-		foreach ($dependencies['classes'] as $class => $module) {
439
-			if (!class_exists($class)) {
440
-				$missingDependencies[] = $module;
441
-			}
442
-		}
443
-		foreach ($dependencies['functions'] as $function => $module) {
444
-			if (!function_exists($function)) {
445
-				$missingDependencies[] = $module;
446
-			}
447
-		}
448
-		foreach ($dependencies['defined'] as $defined => $module) {
449
-			if (!defined($defined)) {
450
-				$missingDependencies[] = $module;
451
-			}
452
-		}
453
-		foreach ($dependencies['ini'] as $setting => $expected) {
454
-			if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
455
-				$invalidIniSettings[] = [$setting, $expected];
456
-			}
457
-		}
458
-
459
-		foreach ($missingDependencies as $missingDependency) {
460
-			$errors[] = [
461
-				'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
462
-				'hint' => $l->t('Please ask your server administrator to install the module.'),
463
-			];
464
-			$webServerRestart = true;
465
-		}
466
-		foreach ($invalidIniSettings as $setting) {
467
-			$errors[] = [
468
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
469
-				'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
470
-			];
471
-			$webServerRestart = true;
472
-		}
473
-
474
-		/**
475
-		 * The mbstring.func_overload check can only be performed if the mbstring
476
-		 * module is installed as it will return null if the checking setting is
477
-		 * not available and thus a check on the boolean value fails.
478
-		 *
479
-		 * TODO: Should probably be implemented in the above generic dependency
480
-		 *       check somehow in the long-term.
481
-		 */
482
-		if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
483
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
484
-			$errors[] = [
485
-				'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]),
486
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
487
-			];
488
-		}
489
-
490
-		if (!self::isAnnotationsWorking()) {
491
-			$errors[] = [
492
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
493
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
494
-			];
495
-		}
496
-
497
-		if (!\OC::$CLI && $webServerRestart) {
498
-			$errors[] = [
499
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
500
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
501
-			];
502
-		}
503
-
504
-		foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
505
-			if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
506
-				$errors[] = [
507
-					'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
508
-					'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
509
-				];
510
-			}
511
-		}
512
-
513
-		// Cache the result of this function
514
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
515
-
516
-		return $errors;
517
-	}
518
-
519
-	/**
520
-	 * Check for correct file permissions of data directory
521
-	 *
522
-	 * @param string $dataDirectory
523
-	 * @return array arrays with error messages and hints
524
-	 * @internal
525
-	 */
526
-	public static function checkDataDirectoryPermissions($dataDirectory) {
527
-		if (!\OC::$server->getConfig()->getSystemValueBool('check_data_directory_permissions', true)) {
528
-			return  [];
529
-		}
530
-
531
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
532
-		if (substr($perms, -1) !== '0') {
533
-			chmod($dataDirectory, 0770);
534
-			clearstatcache();
535
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
536
-			if ($perms[2] !== '0') {
537
-				$l = \OC::$server->getL10N('lib');
538
-				return [[
539
-					'error' => $l->t('Your data directory is readable by other people.'),
540
-					'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'),
541
-				]];
542
-			}
543
-		}
544
-		return [];
545
-	}
546
-
547
-	/**
548
-	 * Check that the data directory exists and is valid by
549
-	 * checking the existence of the ".ncdata" file.
550
-	 *
551
-	 * @param string $dataDirectory data directory path
552
-	 * @return array errors found
553
-	 * @internal
554
-	 */
555
-	public static function checkDataDirectoryValidity($dataDirectory) {
556
-		$l = \OC::$server->getL10N('lib');
557
-		$errors = [];
558
-		if ($dataDirectory[0] !== '/') {
559
-			$errors[] = [
560
-				'error' => $l->t('Your data directory must be an absolute path.'),
561
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
562
-			];
563
-		}
564
-
565
-		if (!file_exists($dataDirectory . '/.ncdata')) {
566
-			$errors[] = [
567
-				'error' => $l->t('Your data directory is invalid.'),
568
-				'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
569
-			];
570
-		}
571
-		return $errors;
572
-	}
573
-
574
-	/**
575
-	 * Check if the user is logged in, redirects to home if not. With
576
-	 * redirect URL parameter to the request URI.
577
-	 *
578
-	 * @deprecated 32.0.0
579
-	 */
580
-	public static function checkLoggedIn(): void {
581
-		// Check if we are a user
582
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
583
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
584
-				'core.login.showLoginForm',
585
-				[
586
-					'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
587
-				]
588
-			)
589
-			);
590
-			exit();
591
-		}
592
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
593
-		if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
594
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
595
-			exit();
596
-		}
597
-	}
598
-
599
-	/**
600
-	 * Check if the user is a admin, redirects to home if not
601
-	 *
602
-	 * @deprecated 32.0.0
603
-	 */
604
-	public static function checkAdminUser(): void {
605
-		self::checkLoggedIn();
606
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
607
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
608
-			exit();
609
-		}
610
-	}
611
-
612
-	/**
613
-	 * Returns the URL of the default page
614
-	 * based on the system configuration and
615
-	 * the apps visible for the current user
616
-	 *
617
-	 * @return string URL
618
-	 * @deprecated 32.0.0 use IURLGenerator's linkToDefaultPageUrl directly
619
-	 */
620
-	public static function getDefaultPageUrl() {
621
-		/** @var IURLGenerator $urlGenerator */
622
-		$urlGenerator = \OC::$server->get(IURLGenerator::class);
623
-		return $urlGenerator->linkToDefaultPageUrl();
624
-	}
625
-
626
-	/**
627
-	 * Redirect to the user default page
628
-	 *
629
-	 * @deprecated 32.0.0
630
-	 */
631
-	public static function redirectToDefaultPage(): void {
632
-		$location = self::getDefaultPageUrl();
633
-		header('Location: ' . $location);
634
-		exit();
635
-	}
636
-
637
-	/**
638
-	 * get an id unique for this instance
639
-	 *
640
-	 * @return string
641
-	 */
642
-	public static function getInstanceId(): string {
643
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
644
-		if (is_null($id)) {
645
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
646
-			$id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
647
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
648
-		}
649
-		return $id;
650
-	}
651
-
652
-	/**
653
-	 * Public function to sanitize HTML
654
-	 *
655
-	 * This function is used to sanitize HTML and should be applied on any
656
-	 * string or array of strings before displaying it on a web page.
657
-	 *
658
-	 * @param string|string[] $value
659
-	 * @return ($value is array ? string[] : string)
660
-	 * @deprecated 32.0.0 use \OCP\Util::sanitizeHTML instead
661
-	 */
662
-	public static function sanitizeHTML($value) {
663
-		if (is_array($value)) {
664
-			$value = array_map(function ($value) {
665
-				return self::sanitizeHTML($value);
666
-			}, $value);
667
-		} else {
668
-			// Specify encoding for PHP<5.4
669
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
670
-		}
671
-		return $value;
672
-	}
673
-
674
-	/**
675
-	 * Public function to encode url parameters
676
-	 *
677
-	 * This function is used to encode path to file before output.
678
-	 * Encoding is done according to RFC 3986 with one exception:
679
-	 * Character '/' is preserved as is.
680
-	 *
681
-	 * @param string $component part of URI to encode
682
-	 * @return string
683
-	 * @deprecated 32.0.0 use \OCP\Util::encodePath instead
684
-	 */
685
-	public static function encodePath($component) {
686
-		$encoded = rawurlencode($component);
687
-		$encoded = str_replace('%2F', '/', $encoded);
688
-		return $encoded;
689
-	}
690
-
691
-	/**
692
-	 * Check if current locale is non-UTF8
693
-	 *
694
-	 * @return bool
695
-	 */
696
-	private static function isNonUTF8Locale() {
697
-		if (function_exists('escapeshellcmd')) {
698
-			return escapeshellcmd('§') === '';
699
-		} elseif (function_exists('escapeshellarg')) {
700
-			return escapeshellarg('§') === '\'\'';
701
-		} else {
702
-			return preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)) === 0;
703
-		}
704
-	}
705
-
706
-	/**
707
-	 * Check if the setlocale call does not work. This can happen if the right
708
-	 * local packages are not available on the server.
709
-	 *
710
-	 * @internal
711
-	 */
712
-	public static function isSetLocaleWorking(): bool {
713
-		if (self::isNonUTF8Locale()) {
714
-			// Borrowed from \Patchwork\Utf8\Bootup::initLocale
715
-			setlocale(LC_ALL, 'C.UTF-8', 'C');
716
-			setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0');
717
-
718
-			// Check again
719
-			if (self::isNonUTF8Locale()) {
720
-				return false;
721
-			}
722
-		}
723
-
724
-		return true;
725
-	}
726
-
727
-	/**
728
-	 * Check if it's possible to get the inline annotations
729
-	 *
730
-	 * @internal
731
-	 */
732
-	public static function isAnnotationsWorking(): bool {
733
-		if (PHP_VERSION_ID >= 80300) {
734
-			/** @psalm-suppress UndefinedMethod */
735
-			$reflection = \ReflectionMethod::createFromMethodName(__METHOD__);
736
-		} else {
737
-			$reflection = new \ReflectionMethod(__METHOD__);
738
-		}
739
-		$docs = $reflection->getDocComment();
740
-
741
-		return (is_string($docs) && strlen($docs) > 50);
742
-	}
743
-
744
-	/**
745
-	 * Check if the PHP module fileinfo is loaded.
746
-	 *
747
-	 * @internal
748
-	 */
749
-	public static function fileInfoLoaded(): bool {
750
-		return function_exists('finfo_open');
751
-	}
752
-
753
-	/**
754
-	 * clear all levels of output buffering
755
-	 *
756
-	 * @return void
757
-	 */
758
-	public static function obEnd() {
759
-		while (ob_get_level()) {
760
-			ob_end_clean();
761
-		}
762
-	}
763
-
764
-	/**
765
-	 * Checks whether the server is running on Mac OS X
766
-	 *
767
-	 * @return bool true if running on Mac OS X, false otherwise
768
-	 */
769
-	public static function runningOnMac() {
770
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
771
-	}
772
-
773
-	/**
774
-	 * Handles the case that there may not be a theme, then check if a "default"
775
-	 * theme exists and take that one
776
-	 *
777
-	 * @return string the theme
778
-	 */
779
-	public static function getTheme() {
780
-		$theme = \OC::$server->getSystemConfig()->getValue('theme', '');
781
-
782
-		if ($theme === '') {
783
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
784
-				$theme = 'default';
785
-			}
786
-		}
787
-
788
-		return $theme;
789
-	}
790
-
791
-	/**
792
-	 * Normalize a unicode string
793
-	 *
794
-	 * @param string $value a not normalized string
795
-	 * @return string The normalized string or the input if the normalization failed
796
-	 */
797
-	public static function normalizeUnicode(string $value): string {
798
-		if (Normalizer::isNormalized($value)) {
799
-			return $value;
800
-		}
801
-
802
-		$normalizedValue = Normalizer::normalize($value);
803
-		if ($normalizedValue === false) {
804
-			\OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
805
-			return $value;
806
-		}
807
-
808
-		return $normalizedValue;
809
-	}
810
-
811
-	/**
812
-	 * Check whether the instance needs to perform an upgrade,
813
-	 * either when the core version is higher or any app requires
814
-	 * an upgrade.
815
-	 *
816
-	 * @param \OC\SystemConfig $config
817
-	 * @return bool whether the core or any app needs an upgrade
818
-	 * @throws \OCP\HintException When the upgrade from the given version is not allowed
819
-	 * @deprecated 32.0.0 Use \OCP\Util::needUpgrade instead
820
-	 */
821
-	public static function needUpgrade(\OC\SystemConfig $config) {
822
-		if ($config->getValue('installed', false)) {
823
-			$installedVersion = $config->getValue('version', '0.0.0');
824
-			$currentVersion = implode('.', \OCP\Util::getVersion());
825
-			$versionDiff = version_compare($currentVersion, $installedVersion);
826
-			if ($versionDiff > 0) {
827
-				return true;
828
-			} elseif ($config->getValue('debug', false) && $versionDiff < 0) {
829
-				// downgrade with debug
830
-				$installedMajor = explode('.', $installedVersion);
831
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
832
-				$currentMajor = explode('.', $currentVersion);
833
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
834
-				if ($installedMajor === $currentMajor) {
835
-					// Same major, allow downgrade for developers
836
-					return true;
837
-				} else {
838
-					// downgrade attempt, throw exception
839
-					throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
840
-				}
841
-			} elseif ($versionDiff < 0) {
842
-				// downgrade attempt, throw exception
843
-				throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
844
-			}
845
-
846
-			// also check for upgrades for apps (independently from the user)
847
-			$apps = \OC_App::getEnabledApps(false, true);
848
-			$shouldUpgrade = false;
849
-			foreach ($apps as $app) {
850
-				if (\OC_App::shouldUpgrade($app)) {
851
-					$shouldUpgrade = true;
852
-					break;
853
-				}
854
-			}
855
-			return $shouldUpgrade;
856
-		} else {
857
-			return false;
858
-		}
859
-	}
25
+    public static $styles = [];
26
+    public static $headers = [];
27
+
28
+    /**
29
+     * Setup the file system
30
+     *
31
+     * @param string|null $user
32
+     * @return boolean
33
+     * @description configure the initial filesystem based on the configuration
34
+     * @suppress PhanDeprecatedFunction
35
+     * @suppress PhanAccessMethodInternal
36
+     */
37
+    public static function setupFS(?string $user = '') {
38
+        // If we are not forced to load a specific user we load the one that is logged in
39
+        if ($user === '') {
40
+            $userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
41
+        } else {
42
+            $userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
43
+        }
44
+
45
+        /** @var SetupManager $setupManager */
46
+        $setupManager = \OC::$server->get(SetupManager::class);
47
+
48
+        if ($userObject) {
49
+            $setupManager->setupForUser($userObject);
50
+        } else {
51
+            $setupManager->setupRoot();
52
+        }
53
+        return true;
54
+    }
55
+
56
+    /**
57
+     * Check if a password is required for each public link
58
+     *
59
+     * @param bool $checkGroupMembership Check group membership exclusion
60
+     * @return bool
61
+     * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkEnforcePassword directly
62
+     */
63
+    public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
64
+        /** @var IManager $shareManager */
65
+        $shareManager = \OC::$server->get(IManager::class);
66
+        return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
67
+    }
68
+
69
+    /**
70
+     * check if sharing is disabled for the current user
71
+     * @param IConfig $config
72
+     * @param IGroupManager $groupManager
73
+     * @param IUser|null $user
74
+     * @return bool
75
+     * @deprecated 32.0.0 use OCP\Share\IManager's sharingDisabledForUser directly
76
+     */
77
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
78
+        /** @var IManager $shareManager */
79
+        $shareManager = \OC::$server->get(IManager::class);
80
+        $userId = $user ? $user->getUID() : null;
81
+        return $shareManager->sharingDisabledForUser($userId);
82
+    }
83
+
84
+    /**
85
+     * check if share API enforces a default expire date
86
+     *
87
+     * @return bool
88
+     * @deprecated 32.0.0 use OCP\Share\IManager's shareApiLinkDefaultExpireDateEnforced directly
89
+     */
90
+    public static function isDefaultExpireDateEnforced() {
91
+        /** @var IManager $shareManager */
92
+        $shareManager = \OC::$server->get(IManager::class);
93
+        return $shareManager->shareApiLinkDefaultExpireDateEnforced();
94
+    }
95
+
96
+    /**
97
+     * Get the quota of a user
98
+     *
99
+     * @param IUser|null $user
100
+     * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
101
+     * @deprecated 9.0.0 - Use \OCP\IUser::getQuota or \OCP\IUser::getQuotaBytes
102
+     */
103
+    public static function getUserQuota(?IUser $user) {
104
+        if (is_null($user)) {
105
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
106
+        }
107
+        $userQuota = $user->getQuota();
108
+        if ($userQuota === 'none') {
109
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
110
+        }
111
+        return \OCP\Util::computerFileSize($userQuota);
112
+    }
113
+
114
+    /**
115
+     * copies the skeleton to the users /files
116
+     *
117
+     * @param string $userId
118
+     * @param \OCP\Files\Folder $userDirectory
119
+     * @throws \OCP\Files\NotFoundException
120
+     * @throws \OCP\Files\NotPermittedException
121
+     * @suppress PhanDeprecatedFunction
122
+     */
123
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
124
+        /** @var LoggerInterface $logger */
125
+        $logger = \OC::$server->get(LoggerInterface::class);
126
+
127
+        $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
128
+        $userLang = \OC::$server->get(IFactory::class)->findLanguage();
129
+        $skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
130
+
131
+        if (!file_exists($skeletonDirectory)) {
132
+            $dialectStart = strpos($userLang, '_');
133
+            if ($dialectStart !== false) {
134
+                $skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
135
+            }
136
+            if ($dialectStart === false || !file_exists($skeletonDirectory)) {
137
+                $skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
138
+            }
139
+            if (!file_exists($skeletonDirectory)) {
140
+                $skeletonDirectory = '';
141
+            }
142
+        }
143
+
144
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
145
+
146
+        if ($instanceId === null) {
147
+            throw new \RuntimeException('no instance id!');
148
+        }
149
+        $appdata = 'appdata_' . $instanceId;
150
+        if ($userId === $appdata) {
151
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
152
+        }
153
+
154
+        if (!empty($skeletonDirectory)) {
155
+            $logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
156
+            self::copyr($skeletonDirectory, $userDirectory);
157
+            // update the file cache
158
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
159
+
160
+            /** @var ITemplateManager $templateManager */
161
+            $templateManager = \OC::$server->get(ITemplateManager::class);
162
+            $templateManager->initializeTemplateDirectory(null, $userId);
163
+        }
164
+    }
165
+
166
+    /**
167
+     * copies a directory recursively by using streams
168
+     *
169
+     * @param string $source
170
+     * @param \OCP\Files\Folder $target
171
+     * @return void
172
+     */
173
+    public static function copyr($source, \OCP\Files\Folder $target) {
174
+        $logger = \OCP\Server::get(LoggerInterface::class);
175
+
176
+        // Verify if folder exists
177
+        $dir = opendir($source);
178
+        if ($dir === false) {
179
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
180
+            return;
181
+        }
182
+
183
+        // Copy the files
184
+        while (false !== ($file = readdir($dir))) {
185
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
186
+                if (is_dir($source . '/' . $file)) {
187
+                    $child = $target->newFolder($file);
188
+                    self::copyr($source . '/' . $file, $child);
189
+                } else {
190
+                    $sourceStream = fopen($source . '/' . $file, 'r');
191
+                    if ($sourceStream === false) {
192
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
193
+                        closedir($dir);
194
+                        return;
195
+                    }
196
+                    $target->newFile($file, $sourceStream);
197
+                }
198
+            }
199
+        }
200
+        closedir($dir);
201
+    }
202
+
203
+    /**
204
+     * @deprecated 32.0.0 Call tearDown directly on SetupManager
205
+     */
206
+    public static function tearDownFS(): void {
207
+        $setupManager = \OCP\Server::get(SetupManager::class);
208
+        $setupManager->tearDown();
209
+    }
210
+
211
+    /**
212
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
213
+     *
214
+     * @param string $application application to get the files from
215
+     * @param string $directory directory within this application (css, js, vendor, etc)
216
+     * @param ?string $file the file inside of the above folder
217
+     */
218
+    private static function generatePath($application, $directory, $file): string {
219
+        if (is_null($file)) {
220
+            $file = $application;
221
+            $application = '';
222
+        }
223
+        if (!empty($application)) {
224
+            return "$application/$directory/$file";
225
+        } else {
226
+            return "$directory/$file";
227
+        }
228
+    }
229
+
230
+    /**
231
+     * add a css file
232
+     *
233
+     * @param string $application application id
234
+     * @param string|null $file filename
235
+     * @param bool $prepend prepend the Style to the beginning of the list
236
+     * @deprecated 32.0.0 Use \OCP\Util::addStyle
237
+     */
238
+    public static function addStyle($application, $file = null, $prepend = false): void {
239
+        $path = OC_Util::generatePath($application, 'css', $file);
240
+        self::addExternalResource($application, $prepend, $path, 'style');
241
+    }
242
+
243
+    /**
244
+     * add a css file from the vendor sub folder
245
+     *
246
+     * @param string $application application id
247
+     * @param string|null $file filename
248
+     * @param bool $prepend prepend the Style to the beginning of the list
249
+     * @deprecated 32.0.0
250
+     */
251
+    public static function addVendorStyle($application, $file = null, $prepend = false): void {
252
+        $path = OC_Util::generatePath($application, 'vendor', $file);
253
+        self::addExternalResource($application, $prepend, $path, 'style');
254
+    }
255
+
256
+    /**
257
+     * add an external resource css/js file
258
+     *
259
+     * @param string $application application id
260
+     * @param bool $prepend prepend the file to the beginning of the list
261
+     * @param string $path
262
+     * @param string $type (script or style)
263
+     */
264
+    private static function addExternalResource($application, $prepend, $path, $type = 'script'): void {
265
+        if ($type === 'style') {
266
+            if (!in_array($path, self::$styles)) {
267
+                if ($prepend === true) {
268
+                    array_unshift(self::$styles, $path);
269
+                } else {
270
+                    self::$styles[] = $path;
271
+                }
272
+            }
273
+        }
274
+    }
275
+
276
+    /**
277
+     * Add a custom element to the header
278
+     * If $text is null then the element will be written as empty element.
279
+     * So use "" to get a closing tag.
280
+     * @param string $tag tag name of the element
281
+     * @param array $attributes array of attributes for the element
282
+     * @param string $text the text content for the element
283
+     * @param bool $prepend prepend the header to the beginning of the list
284
+     * @deprecated 32.0.0 Use \OCP\Util::addHeader instead
285
+     */
286
+    public static function addHeader($tag, $attributes, $text = null, $prepend = false): void {
287
+        $header = [
288
+            'tag' => $tag,
289
+            'attributes' => $attributes,
290
+            'text' => $text
291
+        ];
292
+        if ($prepend === true) {
293
+            array_unshift(self::$headers, $header);
294
+        } else {
295
+            self::$headers[] = $header;
296
+        }
297
+    }
298
+
299
+    /**
300
+     * check if the current server configuration is suitable for ownCloud
301
+     *
302
+     * @return array arrays with error messages and hints
303
+     */
304
+    public static function checkServer(\OC\SystemConfig $config) {
305
+        $l = \OC::$server->getL10N('lib');
306
+        $errors = [];
307
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
308
+
309
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
310
+            // this check needs to be done every time
311
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
312
+        }
313
+
314
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
315
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
316
+            return $errors;
317
+        }
318
+
319
+        $webServerRestart = false;
320
+        $setup = \OCP\Server::get(\OC\Setup::class);
321
+
322
+        $urlGenerator = \OC::$server->getURLGenerator();
323
+
324
+        $availableDatabases = $setup->getSupportedDatabases();
325
+        if (empty($availableDatabases)) {
326
+            $errors[] = [
327
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
328
+                'hint' => '' //TODO: sane hint
329
+            ];
330
+            $webServerRestart = true;
331
+        }
332
+
333
+        // Check if config folder is writable.
334
+        if (!(bool)$config->getValue('config_is_read_only', false)) {
335
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
336
+                $errors[] = [
337
+                    'error' => $l->t('Cannot write into "config" directory.'),
338
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
339
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
340
+                        . $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
341
+                            [ $urlGenerator->linkToDocs('admin-config') ])
342
+                ];
343
+            }
344
+        }
345
+
346
+        // Check if there is a writable install folder.
347
+        if ($config->getValue('appstoreenabled', true)) {
348
+            if (OC_App::getInstallPath() === null
349
+                || !is_writable(OC_App::getInstallPath())
350
+                || !is_readable(OC_App::getInstallPath())
351
+            ) {
352
+                $errors[] = [
353
+                    'error' => $l->t('Cannot write into "apps" directory.'),
354
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
355
+                        . ' or disabling the App Store in the config file.')
356
+                ];
357
+            }
358
+        }
359
+        // Create root dir.
360
+        if ($config->getValue('installed', false)) {
361
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
362
+                $success = @mkdir($CONFIG_DATADIRECTORY);
363
+                if ($success) {
364
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
365
+                } else {
366
+                    $errors[] = [
367
+                        'error' => $l->t('Cannot create "data" directory.'),
368
+                        'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
369
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
370
+                    ];
371
+                }
372
+            } elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
373
+                // is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
374
+                $testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
375
+                $handle = fopen($testFile, 'w');
376
+                if (!$handle || fwrite($handle, 'Test write operation') === false) {
377
+                    $permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
378
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')]);
379
+                    $errors[] = [
380
+                        'error' => $l->t('Your data directory is not writable.'),
381
+                        'hint' => $permissionsHint
382
+                    ];
383
+                } else {
384
+                    fclose($handle);
385
+                    unlink($testFile);
386
+                }
387
+            } else {
388
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
389
+            }
390
+        }
391
+
392
+        if (!OC_Util::isSetLocaleWorking()) {
393
+            $errors[] = [
394
+                'error' => $l->t('Setting locale to %s failed.',
395
+                    ['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
396
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
397
+                'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
398
+            ];
399
+        }
400
+
401
+        // Contains the dependencies that should be checked against
402
+        // classes = class_exists
403
+        // functions = function_exists
404
+        // defined = defined
405
+        // ini = ini_get
406
+        // If the dependency is not found the missing module name is shown to the EndUser
407
+        // When adding new checks always verify that they pass on CI as well
408
+        $dependencies = [
409
+            'classes' => [
410
+                'ZipArchive' => 'zip',
411
+                'DOMDocument' => 'dom',
412
+                'XMLWriter' => 'XMLWriter',
413
+                'XMLReader' => 'XMLReader',
414
+            ],
415
+            'functions' => [
416
+                'xml_parser_create' => 'libxml',
417
+                'mb_strcut' => 'mbstring',
418
+                'ctype_digit' => 'ctype',
419
+                'json_encode' => 'JSON',
420
+                'gd_info' => 'GD',
421
+                'gzencode' => 'zlib',
422
+                'simplexml_load_string' => 'SimpleXML',
423
+                'hash' => 'HASH Message Digest Framework',
424
+                'curl_init' => 'cURL',
425
+                'openssl_verify' => 'OpenSSL',
426
+            ],
427
+            'defined' => [
428
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
429
+            ],
430
+            'ini' => [
431
+                'default_charset' => 'UTF-8',
432
+            ],
433
+        ];
434
+        $missingDependencies = [];
435
+        $invalidIniSettings = [];
436
+
437
+        $iniWrapper = \OC::$server->get(IniGetWrapper::class);
438
+        foreach ($dependencies['classes'] as $class => $module) {
439
+            if (!class_exists($class)) {
440
+                $missingDependencies[] = $module;
441
+            }
442
+        }
443
+        foreach ($dependencies['functions'] as $function => $module) {
444
+            if (!function_exists($function)) {
445
+                $missingDependencies[] = $module;
446
+            }
447
+        }
448
+        foreach ($dependencies['defined'] as $defined => $module) {
449
+            if (!defined($defined)) {
450
+                $missingDependencies[] = $module;
451
+            }
452
+        }
453
+        foreach ($dependencies['ini'] as $setting => $expected) {
454
+            if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
455
+                $invalidIniSettings[] = [$setting, $expected];
456
+            }
457
+        }
458
+
459
+        foreach ($missingDependencies as $missingDependency) {
460
+            $errors[] = [
461
+                'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
462
+                'hint' => $l->t('Please ask your server administrator to install the module.'),
463
+            ];
464
+            $webServerRestart = true;
465
+        }
466
+        foreach ($invalidIniSettings as $setting) {
467
+            $errors[] = [
468
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
469
+                'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
470
+            ];
471
+            $webServerRestart = true;
472
+        }
473
+
474
+        /**
475
+         * The mbstring.func_overload check can only be performed if the mbstring
476
+         * module is installed as it will return null if the checking setting is
477
+         * not available and thus a check on the boolean value fails.
478
+         *
479
+         * TODO: Should probably be implemented in the above generic dependency
480
+         *       check somehow in the long-term.
481
+         */
482
+        if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
483
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
484
+            $errors[] = [
485
+                'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]),
486
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
487
+            ];
488
+        }
489
+
490
+        if (!self::isAnnotationsWorking()) {
491
+            $errors[] = [
492
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
493
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
494
+            ];
495
+        }
496
+
497
+        if (!\OC::$CLI && $webServerRestart) {
498
+            $errors[] = [
499
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
500
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
501
+            ];
502
+        }
503
+
504
+        foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
505
+            if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
506
+                $errors[] = [
507
+                    'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
508
+                    'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
509
+                ];
510
+            }
511
+        }
512
+
513
+        // Cache the result of this function
514
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
515
+
516
+        return $errors;
517
+    }
518
+
519
+    /**
520
+     * Check for correct file permissions of data directory
521
+     *
522
+     * @param string $dataDirectory
523
+     * @return array arrays with error messages and hints
524
+     * @internal
525
+     */
526
+    public static function checkDataDirectoryPermissions($dataDirectory) {
527
+        if (!\OC::$server->getConfig()->getSystemValueBool('check_data_directory_permissions', true)) {
528
+            return  [];
529
+        }
530
+
531
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
532
+        if (substr($perms, -1) !== '0') {
533
+            chmod($dataDirectory, 0770);
534
+            clearstatcache();
535
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
536
+            if ($perms[2] !== '0') {
537
+                $l = \OC::$server->getL10N('lib');
538
+                return [[
539
+                    'error' => $l->t('Your data directory is readable by other people.'),
540
+                    'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'),
541
+                ]];
542
+            }
543
+        }
544
+        return [];
545
+    }
546
+
547
+    /**
548
+     * Check that the data directory exists and is valid by
549
+     * checking the existence of the ".ncdata" file.
550
+     *
551
+     * @param string $dataDirectory data directory path
552
+     * @return array errors found
553
+     * @internal
554
+     */
555
+    public static function checkDataDirectoryValidity($dataDirectory) {
556
+        $l = \OC::$server->getL10N('lib');
557
+        $errors = [];
558
+        if ($dataDirectory[0] !== '/') {
559
+            $errors[] = [
560
+                'error' => $l->t('Your data directory must be an absolute path.'),
561
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
562
+            ];
563
+        }
564
+
565
+        if (!file_exists($dataDirectory . '/.ncdata')) {
566
+            $errors[] = [
567
+                'error' => $l->t('Your data directory is invalid.'),
568
+                'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
569
+            ];
570
+        }
571
+        return $errors;
572
+    }
573
+
574
+    /**
575
+     * Check if the user is logged in, redirects to home if not. With
576
+     * redirect URL parameter to the request URI.
577
+     *
578
+     * @deprecated 32.0.0
579
+     */
580
+    public static function checkLoggedIn(): void {
581
+        // Check if we are a user
582
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
583
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
584
+                'core.login.showLoginForm',
585
+                [
586
+                    'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
587
+                ]
588
+            )
589
+            );
590
+            exit();
591
+        }
592
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
593
+        if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
594
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
595
+            exit();
596
+        }
597
+    }
598
+
599
+    /**
600
+     * Check if the user is a admin, redirects to home if not
601
+     *
602
+     * @deprecated 32.0.0
603
+     */
604
+    public static function checkAdminUser(): void {
605
+        self::checkLoggedIn();
606
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
607
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
608
+            exit();
609
+        }
610
+    }
611
+
612
+    /**
613
+     * Returns the URL of the default page
614
+     * based on the system configuration and
615
+     * the apps visible for the current user
616
+     *
617
+     * @return string URL
618
+     * @deprecated 32.0.0 use IURLGenerator's linkToDefaultPageUrl directly
619
+     */
620
+    public static function getDefaultPageUrl() {
621
+        /** @var IURLGenerator $urlGenerator */
622
+        $urlGenerator = \OC::$server->get(IURLGenerator::class);
623
+        return $urlGenerator->linkToDefaultPageUrl();
624
+    }
625
+
626
+    /**
627
+     * Redirect to the user default page
628
+     *
629
+     * @deprecated 32.0.0
630
+     */
631
+    public static function redirectToDefaultPage(): void {
632
+        $location = self::getDefaultPageUrl();
633
+        header('Location: ' . $location);
634
+        exit();
635
+    }
636
+
637
+    /**
638
+     * get an id unique for this instance
639
+     *
640
+     * @return string
641
+     */
642
+    public static function getInstanceId(): string {
643
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
644
+        if (is_null($id)) {
645
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
646
+            $id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
647
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
648
+        }
649
+        return $id;
650
+    }
651
+
652
+    /**
653
+     * Public function to sanitize HTML
654
+     *
655
+     * This function is used to sanitize HTML and should be applied on any
656
+     * string or array of strings before displaying it on a web page.
657
+     *
658
+     * @param string|string[] $value
659
+     * @return ($value is array ? string[] : string)
660
+     * @deprecated 32.0.0 use \OCP\Util::sanitizeHTML instead
661
+     */
662
+    public static function sanitizeHTML($value) {
663
+        if (is_array($value)) {
664
+            $value = array_map(function ($value) {
665
+                return self::sanitizeHTML($value);
666
+            }, $value);
667
+        } else {
668
+            // Specify encoding for PHP<5.4
669
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
670
+        }
671
+        return $value;
672
+    }
673
+
674
+    /**
675
+     * Public function to encode url parameters
676
+     *
677
+     * This function is used to encode path to file before output.
678
+     * Encoding is done according to RFC 3986 with one exception:
679
+     * Character '/' is preserved as is.
680
+     *
681
+     * @param string $component part of URI to encode
682
+     * @return string
683
+     * @deprecated 32.0.0 use \OCP\Util::encodePath instead
684
+     */
685
+    public static function encodePath($component) {
686
+        $encoded = rawurlencode($component);
687
+        $encoded = str_replace('%2F', '/', $encoded);
688
+        return $encoded;
689
+    }
690
+
691
+    /**
692
+     * Check if current locale is non-UTF8
693
+     *
694
+     * @return bool
695
+     */
696
+    private static function isNonUTF8Locale() {
697
+        if (function_exists('escapeshellcmd')) {
698
+            return escapeshellcmd('§') === '';
699
+        } elseif (function_exists('escapeshellarg')) {
700
+            return escapeshellarg('§') === '\'\'';
701
+        } else {
702
+            return preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)) === 0;
703
+        }
704
+    }
705
+
706
+    /**
707
+     * Check if the setlocale call does not work. This can happen if the right
708
+     * local packages are not available on the server.
709
+     *
710
+     * @internal
711
+     */
712
+    public static function isSetLocaleWorking(): bool {
713
+        if (self::isNonUTF8Locale()) {
714
+            // Borrowed from \Patchwork\Utf8\Bootup::initLocale
715
+            setlocale(LC_ALL, 'C.UTF-8', 'C');
716
+            setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0');
717
+
718
+            // Check again
719
+            if (self::isNonUTF8Locale()) {
720
+                return false;
721
+            }
722
+        }
723
+
724
+        return true;
725
+    }
726
+
727
+    /**
728
+     * Check if it's possible to get the inline annotations
729
+     *
730
+     * @internal
731
+     */
732
+    public static function isAnnotationsWorking(): bool {
733
+        if (PHP_VERSION_ID >= 80300) {
734
+            /** @psalm-suppress UndefinedMethod */
735
+            $reflection = \ReflectionMethod::createFromMethodName(__METHOD__);
736
+        } else {
737
+            $reflection = new \ReflectionMethod(__METHOD__);
738
+        }
739
+        $docs = $reflection->getDocComment();
740
+
741
+        return (is_string($docs) && strlen($docs) > 50);
742
+    }
743
+
744
+    /**
745
+     * Check if the PHP module fileinfo is loaded.
746
+     *
747
+     * @internal
748
+     */
749
+    public static function fileInfoLoaded(): bool {
750
+        return function_exists('finfo_open');
751
+    }
752
+
753
+    /**
754
+     * clear all levels of output buffering
755
+     *
756
+     * @return void
757
+     */
758
+    public static function obEnd() {
759
+        while (ob_get_level()) {
760
+            ob_end_clean();
761
+        }
762
+    }
763
+
764
+    /**
765
+     * Checks whether the server is running on Mac OS X
766
+     *
767
+     * @return bool true if running on Mac OS X, false otherwise
768
+     */
769
+    public static function runningOnMac() {
770
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
771
+    }
772
+
773
+    /**
774
+     * Handles the case that there may not be a theme, then check if a "default"
775
+     * theme exists and take that one
776
+     *
777
+     * @return string the theme
778
+     */
779
+    public static function getTheme() {
780
+        $theme = \OC::$server->getSystemConfig()->getValue('theme', '');
781
+
782
+        if ($theme === '') {
783
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
784
+                $theme = 'default';
785
+            }
786
+        }
787
+
788
+        return $theme;
789
+    }
790
+
791
+    /**
792
+     * Normalize a unicode string
793
+     *
794
+     * @param string $value a not normalized string
795
+     * @return string The normalized string or the input if the normalization failed
796
+     */
797
+    public static function normalizeUnicode(string $value): string {
798
+        if (Normalizer::isNormalized($value)) {
799
+            return $value;
800
+        }
801
+
802
+        $normalizedValue = Normalizer::normalize($value);
803
+        if ($normalizedValue === false) {
804
+            \OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
805
+            return $value;
806
+        }
807
+
808
+        return $normalizedValue;
809
+    }
810
+
811
+    /**
812
+     * Check whether the instance needs to perform an upgrade,
813
+     * either when the core version is higher or any app requires
814
+     * an upgrade.
815
+     *
816
+     * @param \OC\SystemConfig $config
817
+     * @return bool whether the core or any app needs an upgrade
818
+     * @throws \OCP\HintException When the upgrade from the given version is not allowed
819
+     * @deprecated 32.0.0 Use \OCP\Util::needUpgrade instead
820
+     */
821
+    public static function needUpgrade(\OC\SystemConfig $config) {
822
+        if ($config->getValue('installed', false)) {
823
+            $installedVersion = $config->getValue('version', '0.0.0');
824
+            $currentVersion = implode('.', \OCP\Util::getVersion());
825
+            $versionDiff = version_compare($currentVersion, $installedVersion);
826
+            if ($versionDiff > 0) {
827
+                return true;
828
+            } elseif ($config->getValue('debug', false) && $versionDiff < 0) {
829
+                // downgrade with debug
830
+                $installedMajor = explode('.', $installedVersion);
831
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
832
+                $currentMajor = explode('.', $currentVersion);
833
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
834
+                if ($installedMajor === $currentMajor) {
835
+                    // Same major, allow downgrade for developers
836
+                    return true;
837
+                } else {
838
+                    // downgrade attempt, throw exception
839
+                    throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
840
+                }
841
+            } elseif ($versionDiff < 0) {
842
+                // downgrade attempt, throw exception
843
+                throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
844
+            }
845
+
846
+            // also check for upgrades for apps (independently from the user)
847
+            $apps = \OC_App::getEnabledApps(false, true);
848
+            $shouldUpgrade = false;
849
+            foreach ($apps as $app) {
850
+                if (\OC_App::shouldUpgrade($app)) {
851
+                    $shouldUpgrade = true;
852
+                    break;
853
+                }
854
+            }
855
+            return $shouldUpgrade;
856
+        } else {
857
+            return false;
858
+        }
859
+    }
860 860
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
 		/** @var LoggerInterface $logger */
125 125
 		$logger = \OC::$server->get(LoggerInterface::class);
126 126
 
127
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
127
+		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT.'/core/skeleton');
128 128
 		$userLang = \OC::$server->get(IFactory::class)->findLanguage();
129 129
 		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
130 130
 
@@ -146,13 +146,13 @@  discard block
 block discarded – undo
146 146
 		if ($instanceId === null) {
147 147
 			throw new \RuntimeException('no instance id!');
148 148
 		}
149
-		$appdata = 'appdata_' . $instanceId;
149
+		$appdata = 'appdata_'.$instanceId;
150 150
 		if ($userId === $appdata) {
151
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
151
+			throw new \RuntimeException('username is reserved name: '.$appdata);
152 152
 		}
153 153
 
154 154
 		if (!empty($skeletonDirectory)) {
155
-			$logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
155
+			$logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
156 156
 			self::copyr($skeletonDirectory, $userDirectory);
157 157
 			// update the file cache
158 158
 			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
@@ -183,13 +183,13 @@  discard block
 block discarded – undo
183 183
 		// Copy the files
184 184
 		while (false !== ($file = readdir($dir))) {
185 185
 			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
186
-				if (is_dir($source . '/' . $file)) {
186
+				if (is_dir($source.'/'.$file)) {
187 187
 					$child = $target->newFolder($file);
188
-					self::copyr($source . '/' . $file, $child);
188
+					self::copyr($source.'/'.$file, $child);
189 189
 				} else {
190
-					$sourceStream = fopen($source . '/' . $file, 'r');
190
+					$sourceStream = fopen($source.'/'.$file, 'r');
191 191
 					if ($sourceStream === false) {
192
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
192
+						$logger->error(sprintf('Could not fopen "%s"', $source.'/'.$file), ['app' => 'core']);
193 193
 						closedir($dir);
194 194
 						return;
195 195
 					}
@@ -304,7 +304,7 @@  discard block
 block discarded – undo
304 304
 	public static function checkServer(\OC\SystemConfig $config) {
305 305
 		$l = \OC::$server->getL10N('lib');
306 306
 		$errors = [];
307
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
307
+		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT.'/data');
308 308
 
309 309
 		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
310 310
 			// this check needs to be done every time
@@ -331,14 +331,14 @@  discard block
 block discarded – undo
331 331
 		}
332 332
 
333 333
 		// Check if config folder is writable.
334
-		if (!(bool)$config->getValue('config_is_read_only', false)) {
334
+		if (!(bool) $config->getValue('config_is_read_only', false)) {
335 335
 			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
336 336
 				$errors[] = [
337 337
 					'error' => $l->t('Cannot write into "config" directory.'),
338 338
 					'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
339
-						[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
339
+						[$urlGenerator->linkToDocs('admin-dir_permissions')]).'. '
340 340
 						. $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
341
-							[ $urlGenerator->linkToDocs('admin-config') ])
341
+							[$urlGenerator->linkToDocs('admin-config')])
342 342
 				];
343 343
 			}
344 344
 		}
@@ -562,7 +562,7 @@  discard block
 block discarded – undo
562 562
 			];
563 563
 		}
564 564
 
565
-		if (!file_exists($dataDirectory . '/.ncdata')) {
565
+		if (!file_exists($dataDirectory.'/.ncdata')) {
566 566
 			$errors[] = [
567 567
 				'error' => $l->t('Your data directory is invalid.'),
568 568
 				'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
 	public static function checkLoggedIn(): void {
581 581
 		// Check if we are a user
582 582
 		if (!\OC::$server->getUserSession()->isLoggedIn()) {
583
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
583
+			header('Location: '.\OC::$server->getURLGenerator()->linkToRoute(
584 584
 				'core.login.showLoginForm',
585 585
 				[
586 586
 					'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
@@ -591,7 +591,7 @@  discard block
 block discarded – undo
591 591
 		}
592 592
 		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
593 593
 		if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
594
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
594
+			header('Location: '.\OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
595 595
 			exit();
596 596
 		}
597 597
 	}
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
 	public static function checkAdminUser(): void {
605 605
 		self::checkLoggedIn();
606 606
 		if (!OC_User::isAdminUser(OC_User::getUser())) {
607
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
607
+			header('Location: '.\OCP\Util::linkToAbsolute('', 'index.php'));
608 608
 			exit();
609 609
 		}
610 610
 	}
@@ -630,7 +630,7 @@  discard block
 block discarded – undo
630 630
 	 */
631 631
 	public static function redirectToDefaultPage(): void {
632 632
 		$location = self::getDefaultPageUrl();
633
-		header('Location: ' . $location);
633
+		header('Location: '.$location);
634 634
 		exit();
635 635
 	}
636 636
 
@@ -643,7 +643,7 @@  discard block
 block discarded – undo
643 643
 		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
644 644
 		if (is_null($id)) {
645 645
 			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
646
-			$id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
646
+			$id = 'oc'.\OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
647 647
 			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
648 648
 		}
649 649
 		return $id;
@@ -661,12 +661,12 @@  discard block
 block discarded – undo
661 661
 	 */
662 662
 	public static function sanitizeHTML($value) {
663 663
 		if (is_array($value)) {
664
-			$value = array_map(function ($value) {
664
+			$value = array_map(function($value) {
665 665
 				return self::sanitizeHTML($value);
666 666
 			}, $value);
667 667
 		} else {
668 668
 			// Specify encoding for PHP<5.4
669
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
669
+			$value = htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
670 670
 		}
671 671
 		return $value;
672 672
 	}
@@ -780,7 +780,7 @@  discard block
 block discarded – undo
780 780
 		$theme = \OC::$server->getSystemConfig()->getValue('theme', '');
781 781
 
782 782
 		if ($theme === '') {
783
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
783
+			if (is_dir(OC::$SERVERROOT.'/themes/default')) {
784 784
 				$theme = 'default';
785 785
 			}
786 786
 		}
@@ -801,7 +801,7 @@  discard block
 block discarded – undo
801 801
 
802 802
 		$normalizedValue = Normalizer::normalize($value);
803 803
 		if ($normalizedValue === false) {
804
-			\OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
804
+			\OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "'.$value.'"', ['app' => 'core']);
805 805
 			return $value;
806 806
 		}
807 807
 
@@ -828,19 +828,19 @@  discard block
 block discarded – undo
828 828
 			} elseif ($config->getValue('debug', false) && $versionDiff < 0) {
829 829
 				// downgrade with debug
830 830
 				$installedMajor = explode('.', $installedVersion);
831
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
831
+				$installedMajor = $installedMajor[0].'.'.$installedMajor[1];
832 832
 				$currentMajor = explode('.', $currentVersion);
833
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
833
+				$currentMajor = $currentMajor[0].'.'.$currentMajor[1];
834 834
 				if ($installedMajor === $currentMajor) {
835 835
 					// Same major, allow downgrade for developers
836 836
 					return true;
837 837
 				} else {
838 838
 					// downgrade attempt, throw exception
839
-					throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
839
+					throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from '.$installedVersion.' to '.$currentVersion.')');
840 840
 				}
841 841
 			} elseif ($versionDiff < 0) {
842 842
 				// downgrade attempt, throw exception
843
-				throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
843
+				throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from '.$installedVersion.' to '.$currentVersion.')');
844 844
 			}
845 845
 
846 846
 			// also check for upgrades for apps (independently from the user)
Please login to merge, or discard this patch.