Passed
Push — master ( 3a30f6...c2d9c2 )
by Joas
16:09 queued 11s
created
lib/private/legacy/OC_Util.php 1 patch
Indentation   +1162 added lines, -1162 removed lines patch added patch discarded remove patch
@@ -76,1169 +76,1169 @@
 block discarded – undo
76 76
 use Psr\Log\LoggerInterface;
77 77
 
78 78
 class OC_Util {
79
-	public static $scripts = [];
80
-	public static $styles = [];
81
-	public static $headers = [];
82
-
83
-	/** @var array Local cache of version.php */
84
-	private static $versionCache = null;
85
-
86
-	protected static function getAppManager() {
87
-		return \OC::$server->getAppManager();
88
-	}
89
-
90
-	/**
91
-	 * Setup the file system
92
-	 *
93
-	 * @param string|null $user
94
-	 * @return boolean
95
-	 * @description configure the initial filesystem based on the configuration
96
-	 * @suppress PhanDeprecatedFunction
97
-	 * @suppress PhanAccessMethodInternal
98
-	 */
99
-	public static function setupFS(?string $user = '') {
100
-		// If we are not forced to load a specific user we load the one that is logged in
101
-		if ($user === '') {
102
-			$userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
103
-		} else {
104
-			$userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
105
-		}
106
-
107
-		/** @var SetupManager $setupManager */
108
-		$setupManager = \OC::$server->get(SetupManager::class);
109
-
110
-		if ($userObject) {
111
-			$setupManager->setupForUser($userObject);
112
-		} else {
113
-			$setupManager->setupRoot();
114
-		}
115
-		return true;
116
-	}
117
-
118
-	/**
119
-	 * Check if a password is required for each public link
120
-	 *
121
-	 * @param bool $checkGroupMembership Check group membership exclusion
122
-	 * @return boolean
123
-	 * @suppress PhanDeprecatedFunction
124
-	 */
125
-	public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
126
-		/** @var IManager $shareManager */
127
-		$shareManager = \OC::$server->get(IManager::class);
128
-		return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
129
-	}
130
-
131
-	/**
132
-	 * check if sharing is disabled for the current user
133
-	 * @param IConfig $config
134
-	 * @param IGroupManager $groupManager
135
-	 * @param IUser|null $user
136
-	 * @return bool
137
-	 */
138
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
139
-		/** @var IManager $shareManager */
140
-		$shareManager = \OC::$server->get(IManager::class);
141
-		$userId = $user ? $user->getUID() : null;
142
-		return $shareManager->sharingDisabledForUser($userId);
143
-	}
144
-
145
-	/**
146
-	 * check if share API enforces a default expire date
147
-	 *
148
-	 * @return boolean
149
-	 * @suppress PhanDeprecatedFunction
150
-	 */
151
-	public static function isDefaultExpireDateEnforced() {
152
-		/** @var IManager $shareManager */
153
-		$shareManager = \OC::$server->get(IManager::class);
154
-		return $shareManager->shareApiLinkDefaultExpireDateEnforced();
155
-	}
156
-
157
-	/**
158
-	 * Get the quota of a user
159
-	 *
160
-	 * @param IUser|null $user
161
-	 * @return float Quota bytes
162
-	 */
163
-	public static function getUserQuota(?IUser $user) {
164
-		if (is_null($user)) {
165
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
166
-		}
167
-		$userQuota = $user->getQuota();
168
-		if ($userQuota === 'none') {
169
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
170
-		}
171
-		return OC_Helper::computerFileSize($userQuota);
172
-	}
173
-
174
-	/**
175
-	 * copies the skeleton to the users /files
176
-	 *
177
-	 * @param string $userId
178
-	 * @param \OCP\Files\Folder $userDirectory
179
-	 * @throws \OCP\Files\NotFoundException
180
-	 * @throws \OCP\Files\NotPermittedException
181
-	 * @suppress PhanDeprecatedFunction
182
-	 */
183
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
184
-		/** @var LoggerInterface $logger */
185
-		$logger = \OC::$server->get(LoggerInterface::class);
186
-
187
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
188
-		$userLang = \OC::$server->getL10NFactory()->findLanguage();
189
-		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
190
-
191
-		if (!file_exists($skeletonDirectory)) {
192
-			$dialectStart = strpos($userLang, '_');
193
-			if ($dialectStart !== false) {
194
-				$skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
195
-			}
196
-			if ($dialectStart === false || !file_exists($skeletonDirectory)) {
197
-				$skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
198
-			}
199
-			if (!file_exists($skeletonDirectory)) {
200
-				$skeletonDirectory = '';
201
-			}
202
-		}
203
-
204
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
205
-
206
-		if ($instanceId === null) {
207
-			throw new \RuntimeException('no instance id!');
208
-		}
209
-		$appdata = 'appdata_' . $instanceId;
210
-		if ($userId === $appdata) {
211
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
212
-		}
213
-
214
-		if (!empty($skeletonDirectory)) {
215
-			$logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
216
-			self::copyr($skeletonDirectory, $userDirectory);
217
-			// update the file cache
218
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
219
-
220
-			/** @var ITemplateManager $templateManager */
221
-			$templateManager = \OC::$server->get(ITemplateManager::class);
222
-			$templateManager->initializeTemplateDirectory(null, $userId);
223
-		}
224
-	}
225
-
226
-	/**
227
-	 * copies a directory recursively by using streams
228
-	 *
229
-	 * @param string $source
230
-	 * @param \OCP\Files\Folder $target
231
-	 * @return void
232
-	 */
233
-	public static function copyr($source, \OCP\Files\Folder $target) {
234
-		$logger = \OC::$server->getLogger();
235
-
236
-		// Verify if folder exists
237
-		$dir = opendir($source);
238
-		if ($dir === false) {
239
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
240
-			return;
241
-		}
242
-
243
-		// Copy the files
244
-		while (false !== ($file = readdir($dir))) {
245
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
246
-				if (is_dir($source . '/' . $file)) {
247
-					$child = $target->newFolder($file);
248
-					self::copyr($source . '/' . $file, $child);
249
-				} else {
250
-					$child = $target->newFile($file);
251
-					$sourceStream = fopen($source . '/' . $file, 'r');
252
-					if ($sourceStream === false) {
253
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
254
-						closedir($dir);
255
-						return;
256
-					}
257
-					stream_copy_to_stream($sourceStream, $child->fopen('w'));
258
-				}
259
-			}
260
-		}
261
-		closedir($dir);
262
-	}
263
-
264
-	/**
265
-	 * @return void
266
-	 * @suppress PhanUndeclaredMethod
267
-	 */
268
-	public static function tearDownFS() {
269
-		/** @var SetupManager $setupManager */
270
-		$setupManager = \OC::$server->get(SetupManager::class);
271
-		$setupManager->tearDown();
272
-	}
273
-
274
-	/**
275
-	 * get the current installed version of ownCloud
276
-	 *
277
-	 * @return array
278
-	 */
279
-	public static function getVersion() {
280
-		OC_Util::loadVersion();
281
-		return self::$versionCache['OC_Version'];
282
-	}
283
-
284
-	/**
285
-	 * get the current installed version string of ownCloud
286
-	 *
287
-	 * @return string
288
-	 */
289
-	public static function getVersionString() {
290
-		OC_Util::loadVersion();
291
-		return self::$versionCache['OC_VersionString'];
292
-	}
293
-
294
-	/**
295
-	 * @deprecated the value is of no use anymore
296
-	 * @return string
297
-	 */
298
-	public static function getEditionString() {
299
-		return '';
300
-	}
301
-
302
-	/**
303
-	 * @description get the update channel of the current installed of ownCloud.
304
-	 * @return string
305
-	 */
306
-	public static function getChannel() {
307
-		OC_Util::loadVersion();
308
-		return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
309
-	}
310
-
311
-	/**
312
-	 * @description get the build number of the current installed of ownCloud.
313
-	 * @return string
314
-	 */
315
-	public static function getBuild() {
316
-		OC_Util::loadVersion();
317
-		return self::$versionCache['OC_Build'];
318
-	}
319
-
320
-	/**
321
-	 * @description load the version.php into the session as cache
322
-	 * @suppress PhanUndeclaredVariable
323
-	 */
324
-	private static function loadVersion() {
325
-		if (self::$versionCache !== null) {
326
-			return;
327
-		}
328
-
329
-		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
330
-		require OC::$SERVERROOT . '/version.php';
331
-		/** @var int $timestamp */
332
-		self::$versionCache['OC_Version_Timestamp'] = $timestamp;
333
-		/** @var string $OC_Version */
334
-		self::$versionCache['OC_Version'] = $OC_Version;
335
-		/** @var string $OC_VersionString */
336
-		self::$versionCache['OC_VersionString'] = $OC_VersionString;
337
-		/** @var string $OC_Build */
338
-		self::$versionCache['OC_Build'] = $OC_Build;
339
-
340
-		/** @var string $OC_Channel */
341
-		self::$versionCache['OC_Channel'] = $OC_Channel;
342
-	}
343
-
344
-	/**
345
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
346
-	 *
347
-	 * @param string $application application to get the files from
348
-	 * @param string $directory directory within this application (css, js, vendor, etc)
349
-	 * @param string $file the file inside of the above folder
350
-	 * @return string the path
351
-	 */
352
-	private static function generatePath($application, $directory, $file) {
353
-		if (is_null($file)) {
354
-			$file = $application;
355
-			$application = "";
356
-		}
357
-		if (!empty($application)) {
358
-			return "$application/$directory/$file";
359
-		} else {
360
-			return "$directory/$file";
361
-		}
362
-	}
363
-
364
-	/**
365
-	 * add a javascript file
366
-	 *
367
-	 * @deprecated 24.0.0 - Use \OCP\Util::addScript
368
-	 *
369
-	 * @param string $application application id
370
-	 * @param string|null $file filename
371
-	 * @param bool $prepend prepend the Script to the beginning of the list
372
-	 * @return void
373
-	 */
374
-	public static function addScript($application, $file = null, $prepend = false) {
375
-		$path = OC_Util::generatePath($application, 'js', $file);
376
-
377
-		// core js files need separate handling
378
-		if ($application !== 'core' && $file !== null) {
379
-			self::addTranslations($application);
380
-		}
381
-		self::addExternalResource($application, $prepend, $path, "script");
382
-	}
383
-
384
-	/**
385
-	 * add a javascript file from the vendor sub folder
386
-	 *
387
-	 * @param string $application application id
388
-	 * @param string|null $file filename
389
-	 * @param bool $prepend prepend the Script to the beginning of the list
390
-	 * @return void
391
-	 */
392
-	public static function addVendorScript($application, $file = null, $prepend = false) {
393
-		$path = OC_Util::generatePath($application, 'vendor', $file);
394
-		self::addExternalResource($application, $prepend, $path, "script");
395
-	}
396
-
397
-	/**
398
-	 * add a translation JS file
399
-	 *
400
-	 * @deprecated 24.0.0
401
-	 *
402
-	 * @param string $application application id
403
-	 * @param string|null $languageCode language code, defaults to the current language
404
-	 * @param bool|null $prepend prepend the Script to the beginning of the list
405
-	 */
406
-	public static function addTranslations($application, $languageCode = null, $prepend = false) {
407
-		if (is_null($languageCode)) {
408
-			$languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
409
-		}
410
-		if (!empty($application)) {
411
-			$path = "$application/l10n/$languageCode";
412
-		} else {
413
-			$path = "l10n/$languageCode";
414
-		}
415
-		self::addExternalResource($application, $prepend, $path, "script");
416
-	}
417
-
418
-	/**
419
-	 * add a css file
420
-	 *
421
-	 * @param string $application application id
422
-	 * @param string|null $file filename
423
-	 * @param bool $prepend prepend the Style to the beginning of the list
424
-	 * @return void
425
-	 */
426
-	public static function addStyle($application, $file = null, $prepend = false) {
427
-		$path = OC_Util::generatePath($application, 'css', $file);
428
-		self::addExternalResource($application, $prepend, $path, "style");
429
-	}
430
-
431
-	/**
432
-	 * add a css file from the vendor sub folder
433
-	 *
434
-	 * @param string $application application id
435
-	 * @param string|null $file filename
436
-	 * @param bool $prepend prepend the Style to the beginning of the list
437
-	 * @return void
438
-	 */
439
-	public static function addVendorStyle($application, $file = null, $prepend = false) {
440
-		$path = OC_Util::generatePath($application, 'vendor', $file);
441
-		self::addExternalResource($application, $prepend, $path, "style");
442
-	}
443
-
444
-	/**
445
-	 * add an external resource css/js file
446
-	 *
447
-	 * @param string $application application id
448
-	 * @param bool $prepend prepend the file to the beginning of the list
449
-	 * @param string $path
450
-	 * @param string $type (script or style)
451
-	 * @return void
452
-	 */
453
-	private static function addExternalResource($application, $prepend, $path, $type = "script") {
454
-		if ($type === "style") {
455
-			if (!in_array($path, self::$styles)) {
456
-				if ($prepend === true) {
457
-					array_unshift(self::$styles, $path);
458
-				} else {
459
-					self::$styles[] = $path;
460
-				}
461
-			}
462
-		} elseif ($type === "script") {
463
-			if (!in_array($path, self::$scripts)) {
464
-				if ($prepend === true) {
465
-					array_unshift(self::$scripts, $path);
466
-				} else {
467
-					self::$scripts [] = $path;
468
-				}
469
-			}
470
-		}
471
-	}
472
-
473
-	/**
474
-	 * Add a custom element to the header
475
-	 * If $text is null then the element will be written as empty element.
476
-	 * So use "" to get a closing tag.
477
-	 * @param string $tag tag name of the element
478
-	 * @param array $attributes array of attributes for the element
479
-	 * @param string $text the text content for the element
480
-	 * @param bool $prepend prepend the header to the beginning of the list
481
-	 */
482
-	public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
483
-		$header = [
484
-			'tag' => $tag,
485
-			'attributes' => $attributes,
486
-			'text' => $text
487
-		];
488
-		if ($prepend === true) {
489
-			array_unshift(self::$headers, $header);
490
-		} else {
491
-			self::$headers[] = $header;
492
-		}
493
-	}
494
-
495
-	/**
496
-	 * check if the current server configuration is suitable for ownCloud
497
-	 *
498
-	 * @param \OC\SystemConfig $config
499
-	 * @return array arrays with error messages and hints
500
-	 */
501
-	public static function checkServer(\OC\SystemConfig $config) {
502
-		$l = \OC::$server->getL10N('lib');
503
-		$errors = [];
504
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
505
-
506
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
507
-			// this check needs to be done every time
508
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
509
-		}
510
-
511
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
512
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
513
-			return $errors;
514
-		}
515
-
516
-		$webServerRestart = false;
517
-		$setup = new \OC\Setup(
518
-			$config,
519
-			\OC::$server->get(IniGetWrapper::class),
520
-			\OC::$server->getL10N('lib'),
521
-			\OC::$server->get(\OCP\Defaults::class),
522
-			\OC::$server->get(LoggerInterface::class),
523
-			\OC::$server->getSecureRandom(),
524
-			\OC::$server->get(\OC\Installer::class)
525
-		);
526
-
527
-		$urlGenerator = \OC::$server->getURLGenerator();
528
-
529
-		$availableDatabases = $setup->getSupportedDatabases();
530
-		if (empty($availableDatabases)) {
531
-			$errors[] = [
532
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
533
-				'hint' => '' //TODO: sane hint
534
-			];
535
-			$webServerRestart = true;
536
-		}
537
-
538
-		// Check if config folder is writable.
539
-		if (!OC_Helper::isReadOnlyConfigEnabled()) {
540
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
541
-				$errors[] = [
542
-					'error' => $l->t('Cannot write into "config" directory.'),
543
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
544
-						[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
545
-						. $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',
546
-						[ $urlGenerator->linkToDocs('admin-config') ])
547
-				];
548
-			}
549
-		}
550
-
551
-		// Check if there is a writable install folder.
552
-		if ($config->getValue('appstoreenabled', true)) {
553
-			if (OC_App::getInstallPath() === null
554
-				|| !is_writable(OC_App::getInstallPath())
555
-				|| !is_readable(OC_App::getInstallPath())
556
-			) {
557
-				$errors[] = [
558
-					'error' => $l->t('Cannot write into "apps" directory.'),
559
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
560
-						. ' or disabling the App Store in the config file.')
561
-				];
562
-			}
563
-		}
564
-		// Create root dir.
565
-		if ($config->getValue('installed', false)) {
566
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
567
-				$success = @mkdir($CONFIG_DATADIRECTORY);
568
-				if ($success) {
569
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
570
-				} else {
571
-					$errors[] = [
572
-						'error' => $l->t('Cannot create "data" directory.'),
573
-						'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
574
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
575
-					];
576
-				}
577
-			} elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
578
-				// is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
579
-				$testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
580
-				$handle = fopen($testFile, 'w');
581
-				if (!$handle || fwrite($handle, 'Test write operation') === false) {
582
-					$permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
583
-						[$urlGenerator->linkToDocs('admin-dir_permissions')]);
584
-					$errors[] = [
585
-						'error' => $l->t('Your data directory is not writable.'),
586
-						'hint' => $permissionsHint
587
-					];
588
-				} else {
589
-					fclose($handle);
590
-					unlink($testFile);
591
-				}
592
-			} else {
593
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
594
-			}
595
-		}
596
-
597
-		if (!OC_Util::isSetLocaleWorking()) {
598
-			$errors[] = [
599
-				'error' => $l->t('Setting locale to %s failed.',
600
-					['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
601
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
602
-				'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
603
-			];
604
-		}
605
-
606
-		// Contains the dependencies that should be checked against
607
-		// classes = class_exists
608
-		// functions = function_exists
609
-		// defined = defined
610
-		// ini = ini_get
611
-		// If the dependency is not found the missing module name is shown to the EndUser
612
-		// When adding new checks always verify that they pass on Travis as well
613
-		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
614
-		$dependencies = [
615
-			'classes' => [
616
-				'ZipArchive' => 'zip',
617
-				'DOMDocument' => 'dom',
618
-				'XMLWriter' => 'XMLWriter',
619
-				'XMLReader' => 'XMLReader',
620
-			],
621
-			'functions' => [
622
-				'xml_parser_create' => 'libxml',
623
-				'mb_strcut' => 'mbstring',
624
-				'ctype_digit' => 'ctype',
625
-				'json_encode' => 'JSON',
626
-				'gd_info' => 'GD',
627
-				'gzencode' => 'zlib',
628
-				'simplexml_load_string' => 'SimpleXML',
629
-				'hash' => 'HASH Message Digest Framework',
630
-				'curl_init' => 'cURL',
631
-				'openssl_verify' => 'OpenSSL',
632
-			],
633
-			'defined' => [
634
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
635
-			],
636
-			'ini' => [
637
-				'default_charset' => 'UTF-8',
638
-			],
639
-		];
640
-		$missingDependencies = [];
641
-		$invalidIniSettings = [];
642
-
643
-		$iniWrapper = \OC::$server->get(IniGetWrapper::class);
644
-		foreach ($dependencies['classes'] as $class => $module) {
645
-			if (!class_exists($class)) {
646
-				$missingDependencies[] = $module;
647
-			}
648
-		}
649
-		foreach ($dependencies['functions'] as $function => $module) {
650
-			if (!function_exists($function)) {
651
-				$missingDependencies[] = $module;
652
-			}
653
-		}
654
-		foreach ($dependencies['defined'] as $defined => $module) {
655
-			if (!defined($defined)) {
656
-				$missingDependencies[] = $module;
657
-			}
658
-		}
659
-		foreach ($dependencies['ini'] as $setting => $expected) {
660
-			if (is_bool($expected)) {
661
-				if ($iniWrapper->getBool($setting) !== $expected) {
662
-					$invalidIniSettings[] = [$setting, $expected];
663
-				}
664
-			}
665
-			if (is_int($expected)) {
666
-				if ($iniWrapper->getNumeric($setting) !== $expected) {
667
-					$invalidIniSettings[] = [$setting, $expected];
668
-				}
669
-			}
670
-			if (is_string($expected)) {
671
-				if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
672
-					$invalidIniSettings[] = [$setting, $expected];
673
-				}
674
-			}
675
-		}
676
-
677
-		foreach ($missingDependencies as $missingDependency) {
678
-			$errors[] = [
679
-				'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
680
-				'hint' => $l->t('Please ask your server administrator to install the module.'),
681
-			];
682
-			$webServerRestart = true;
683
-		}
684
-		foreach ($invalidIniSettings as $setting) {
685
-			if (is_bool($setting[1])) {
686
-				$setting[1] = $setting[1] ? 'on' : 'off';
687
-			}
688
-			$errors[] = [
689
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
690
-				'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
691
-			];
692
-			$webServerRestart = true;
693
-		}
694
-
695
-		/**
696
-		 * The mbstring.func_overload check can only be performed if the mbstring
697
-		 * module is installed as it will return null if the checking setting is
698
-		 * not available and thus a check on the boolean value fails.
699
-		 *
700
-		 * TODO: Should probably be implemented in the above generic dependency
701
-		 *       check somehow in the long-term.
702
-		 */
703
-		if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
704
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
705
-			$errors[] = [
706
-				'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')]),
707
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
708
-			];
709
-		}
710
-
711
-		if (function_exists('xml_parser_create') &&
712
-			LIBXML_LOADED_VERSION < 20700) {
713
-			$version = LIBXML_LOADED_VERSION;
714
-			$major = floor($version / 10000);
715
-			$version -= ($major * 10000);
716
-			$minor = floor($version / 100);
717
-			$version -= ($minor * 100);
718
-			$patch = $version;
719
-			$errors[] = [
720
-				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
721
-				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
722
-			];
723
-		}
724
-
725
-		if (!self::isAnnotationsWorking()) {
726
-			$errors[] = [
727
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
728
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
729
-			];
730
-		}
731
-
732
-		if (!\OC::$CLI && $webServerRestart) {
733
-			$errors[] = [
734
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
735
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
736
-			];
737
-		}
738
-
739
-		foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
740
-			if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
741
-				$errors[] = [
742
-					'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
743
-					'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
744
-				];
745
-			}
746
-		}
747
-
748
-		$errors = array_merge($errors, self::checkDatabaseVersion());
749
-
750
-		// Cache the result of this function
751
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
752
-
753
-		return $errors;
754
-	}
755
-
756
-	/**
757
-	 * Check the database version
758
-	 *
759
-	 * @return array errors array
760
-	 */
761
-	public static function checkDatabaseVersion() {
762
-		$l = \OC::$server->getL10N('lib');
763
-		$errors = [];
764
-		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
765
-		if ($dbType === 'pgsql') {
766
-			// check PostgreSQL version
767
-			try {
768
-				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
769
-				$data = $result->fetchRow();
770
-				$result->closeCursor();
771
-				if (isset($data['server_version'])) {
772
-					$version = $data['server_version'];
773
-					if (version_compare($version, '9.0.0', '<')) {
774
-						$errors[] = [
775
-							'error' => $l->t('PostgreSQL >= 9 required.'),
776
-							'hint' => $l->t('Please upgrade your database version.')
777
-						];
778
-					}
779
-				}
780
-			} catch (\Doctrine\DBAL\Exception $e) {
781
-				$logger = \OC::$server->getLogger();
782
-				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
783
-				$logger->logException($e);
784
-			}
785
-		}
786
-		return $errors;
787
-	}
788
-
789
-	/**
790
-	 * Check for correct file permissions of data directory
791
-	 *
792
-	 * @param string $dataDirectory
793
-	 * @return array arrays with error messages and hints
794
-	 */
795
-	public static function checkDataDirectoryPermissions($dataDirectory) {
796
-		if (\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
797
-			return  [];
798
-		}
799
-
800
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
801
-		if (substr($perms, -1) !== '0') {
802
-			chmod($dataDirectory, 0770);
803
-			clearstatcache();
804
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
805
-			if ($perms[2] !== '0') {
806
-				$l = \OC::$server->getL10N('lib');
807
-				return [[
808
-					'error' => $l->t('Your data directory is readable by other users.'),
809
-					'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'),
810
-				]];
811
-			}
812
-		}
813
-		return [];
814
-	}
815
-
816
-	/**
817
-	 * Check that the data directory exists and is valid by
818
-	 * checking the existence of the ".ocdata" file.
819
-	 *
820
-	 * @param string $dataDirectory data directory path
821
-	 * @return array errors found
822
-	 */
823
-	public static function checkDataDirectoryValidity($dataDirectory) {
824
-		$l = \OC::$server->getL10N('lib');
825
-		$errors = [];
826
-		if ($dataDirectory[0] !== '/') {
827
-			$errors[] = [
828
-				'error' => $l->t('Your data directory must be an absolute path.'),
829
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
830
-			];
831
-		}
832
-		if (!file_exists($dataDirectory . '/.ocdata')) {
833
-			$errors[] = [
834
-				'error' => $l->t('Your data directory is invalid.'),
835
-				'hint' => $l->t('Ensure there is a file called ".ocdata"' .
836
-					' in the root of the data directory.')
837
-			];
838
-		}
839
-		return $errors;
840
-	}
841
-
842
-	/**
843
-	 * Check if the user is logged in, redirects to home if not. With
844
-	 * redirect URL parameter to the request URI.
845
-	 *
846
-	 * @return void
847
-	 */
848
-	public static function checkLoggedIn() {
849
-		// Check if we are a user
850
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
851
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
852
-						'core.login.showLoginForm',
853
-						[
854
-							'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
855
-						]
856
-					)
857
-			);
858
-			exit();
859
-		}
860
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
861
-		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
862
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
863
-			exit();
864
-		}
865
-	}
866
-
867
-	/**
868
-	 * Check if the user is a admin, redirects to home if not
869
-	 *
870
-	 * @return void
871
-	 */
872
-	public static function checkAdminUser() {
873
-		OC_Util::checkLoggedIn();
874
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
875
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
876
-			exit();
877
-		}
878
-	}
879
-
880
-	/**
881
-	 * Returns the URL of the default page
882
-	 * based on the system configuration and
883
-	 * the apps visible for the current user
884
-	 *
885
-	 * @return string URL
886
-	 * @suppress PhanDeprecatedFunction
887
-	 */
888
-	public static function getDefaultPageUrl() {
889
-		/** @var IURLGenerator $urlGenerator */
890
-		$urlGenerator = \OC::$server->get(IURLGenerator::class);
891
-		return $urlGenerator->linkToDefaultPageUrl();
892
-	}
893
-
894
-	/**
895
-	 * Redirect to the user default page
896
-	 *
897
-	 * @return void
898
-	 */
899
-	public static function redirectToDefaultPage() {
900
-		$location = self::getDefaultPageUrl();
901
-		header('Location: ' . $location);
902
-		exit();
903
-	}
904
-
905
-	/**
906
-	 * get an id unique for this instance
907
-	 *
908
-	 * @return string
909
-	 */
910
-	public static function getInstanceId() {
911
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
912
-		if (is_null($id)) {
913
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
914
-			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
915
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
916
-		}
917
-		return $id;
918
-	}
919
-
920
-	/**
921
-	 * Public function to sanitize HTML
922
-	 *
923
-	 * This function is used to sanitize HTML and should be applied on any
924
-	 * string or array of strings before displaying it on a web page.
925
-	 *
926
-	 * @param string|string[] $value
927
-	 * @return string|string[] an array of sanitized strings or a single sanitized string, depends on the input parameter.
928
-	 */
929
-	public static function sanitizeHTML($value) {
930
-		if (is_array($value)) {
931
-			/** @var string[] $value */
932
-			$value = array_map(function ($value) {
933
-				return self::sanitizeHTML($value);
934
-			}, $value);
935
-		} else {
936
-			// Specify encoding for PHP<5.4
937
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
938
-		}
939
-		return $value;
940
-	}
941
-
942
-	/**
943
-	 * Public function to encode url parameters
944
-	 *
945
-	 * This function is used to encode path to file before output.
946
-	 * Encoding is done according to RFC 3986 with one exception:
947
-	 * Character '/' is preserved as is.
948
-	 *
949
-	 * @param string $component part of URI to encode
950
-	 * @return string
951
-	 */
952
-	public static function encodePath($component) {
953
-		$encoded = rawurlencode($component);
954
-		$encoded = str_replace('%2F', '/', $encoded);
955
-		return $encoded;
956
-	}
957
-
958
-
959
-	public function createHtaccessTestFile(\OCP\IConfig $config) {
960
-		// php dev server does not support htaccess
961
-		if (php_sapi_name() === 'cli-server') {
962
-			return false;
963
-		}
964
-
965
-		// testdata
966
-		$fileName = '/htaccesstest.txt';
967
-		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
968
-
969
-		// creating a test file
970
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
971
-
972
-		if (file_exists($testFile)) {// already running this test, possible recursive call
973
-			return false;
974
-		}
975
-
976
-		$fp = @fopen($testFile, 'w');
977
-		if (!$fp) {
978
-			throw new \OCP\HintException('Can\'t create test file to check for working .htaccess file.',
979
-				'Make sure it is possible for the web server to write to ' . $testFile);
980
-		}
981
-		fwrite($fp, $testContent);
982
-		fclose($fp);
983
-
984
-		return $testContent;
985
-	}
986
-
987
-	/**
988
-	 * Check if the .htaccess file is working
989
-	 *
990
-	 * @param \OCP\IConfig $config
991
-	 * @return bool
992
-	 * @throws Exception
993
-	 * @throws \OCP\HintException If the test file can't get written.
994
-	 */
995
-	public function isHtaccessWorking(\OCP\IConfig $config) {
996
-		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
997
-			return true;
998
-		}
999
-
1000
-		$testContent = $this->createHtaccessTestFile($config);
1001
-		if ($testContent === false) {
1002
-			return false;
1003
-		}
1004
-
1005
-		$fileName = '/htaccesstest.txt';
1006
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1007
-
1008
-		// accessing the file via http
1009
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1010
-		try {
1011
-			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1012
-		} catch (\Exception $e) {
1013
-			$content = false;
1014
-		}
1015
-
1016
-		if (strpos($url, 'https:') === 0) {
1017
-			$url = 'http:' . substr($url, 6);
1018
-		} else {
1019
-			$url = 'https:' . substr($url, 5);
1020
-		}
1021
-
1022
-		try {
1023
-			$fallbackContent = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1024
-		} catch (\Exception $e) {
1025
-			$fallbackContent = false;
1026
-		}
1027
-
1028
-		// cleanup
1029
-		@unlink($testFile);
1030
-
1031
-		/*
79
+    public static $scripts = [];
80
+    public static $styles = [];
81
+    public static $headers = [];
82
+
83
+    /** @var array Local cache of version.php */
84
+    private static $versionCache = null;
85
+
86
+    protected static function getAppManager() {
87
+        return \OC::$server->getAppManager();
88
+    }
89
+
90
+    /**
91
+     * Setup the file system
92
+     *
93
+     * @param string|null $user
94
+     * @return boolean
95
+     * @description configure the initial filesystem based on the configuration
96
+     * @suppress PhanDeprecatedFunction
97
+     * @suppress PhanAccessMethodInternal
98
+     */
99
+    public static function setupFS(?string $user = '') {
100
+        // If we are not forced to load a specific user we load the one that is logged in
101
+        if ($user === '') {
102
+            $userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
103
+        } else {
104
+            $userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
105
+        }
106
+
107
+        /** @var SetupManager $setupManager */
108
+        $setupManager = \OC::$server->get(SetupManager::class);
109
+
110
+        if ($userObject) {
111
+            $setupManager->setupForUser($userObject);
112
+        } else {
113
+            $setupManager->setupRoot();
114
+        }
115
+        return true;
116
+    }
117
+
118
+    /**
119
+     * Check if a password is required for each public link
120
+     *
121
+     * @param bool $checkGroupMembership Check group membership exclusion
122
+     * @return boolean
123
+     * @suppress PhanDeprecatedFunction
124
+     */
125
+    public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
126
+        /** @var IManager $shareManager */
127
+        $shareManager = \OC::$server->get(IManager::class);
128
+        return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
129
+    }
130
+
131
+    /**
132
+     * check if sharing is disabled for the current user
133
+     * @param IConfig $config
134
+     * @param IGroupManager $groupManager
135
+     * @param IUser|null $user
136
+     * @return bool
137
+     */
138
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
139
+        /** @var IManager $shareManager */
140
+        $shareManager = \OC::$server->get(IManager::class);
141
+        $userId = $user ? $user->getUID() : null;
142
+        return $shareManager->sharingDisabledForUser($userId);
143
+    }
144
+
145
+    /**
146
+     * check if share API enforces a default expire date
147
+     *
148
+     * @return boolean
149
+     * @suppress PhanDeprecatedFunction
150
+     */
151
+    public static function isDefaultExpireDateEnforced() {
152
+        /** @var IManager $shareManager */
153
+        $shareManager = \OC::$server->get(IManager::class);
154
+        return $shareManager->shareApiLinkDefaultExpireDateEnforced();
155
+    }
156
+
157
+    /**
158
+     * Get the quota of a user
159
+     *
160
+     * @param IUser|null $user
161
+     * @return float Quota bytes
162
+     */
163
+    public static function getUserQuota(?IUser $user) {
164
+        if (is_null($user)) {
165
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
166
+        }
167
+        $userQuota = $user->getQuota();
168
+        if ($userQuota === 'none') {
169
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
170
+        }
171
+        return OC_Helper::computerFileSize($userQuota);
172
+    }
173
+
174
+    /**
175
+     * copies the skeleton to the users /files
176
+     *
177
+     * @param string $userId
178
+     * @param \OCP\Files\Folder $userDirectory
179
+     * @throws \OCP\Files\NotFoundException
180
+     * @throws \OCP\Files\NotPermittedException
181
+     * @suppress PhanDeprecatedFunction
182
+     */
183
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
184
+        /** @var LoggerInterface $logger */
185
+        $logger = \OC::$server->get(LoggerInterface::class);
186
+
187
+        $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
188
+        $userLang = \OC::$server->getL10NFactory()->findLanguage();
189
+        $skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
190
+
191
+        if (!file_exists($skeletonDirectory)) {
192
+            $dialectStart = strpos($userLang, '_');
193
+            if ($dialectStart !== false) {
194
+                $skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
195
+            }
196
+            if ($dialectStart === false || !file_exists($skeletonDirectory)) {
197
+                $skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
198
+            }
199
+            if (!file_exists($skeletonDirectory)) {
200
+                $skeletonDirectory = '';
201
+            }
202
+        }
203
+
204
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
205
+
206
+        if ($instanceId === null) {
207
+            throw new \RuntimeException('no instance id!');
208
+        }
209
+        $appdata = 'appdata_' . $instanceId;
210
+        if ($userId === $appdata) {
211
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
212
+        }
213
+
214
+        if (!empty($skeletonDirectory)) {
215
+            $logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
216
+            self::copyr($skeletonDirectory, $userDirectory);
217
+            // update the file cache
218
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
219
+
220
+            /** @var ITemplateManager $templateManager */
221
+            $templateManager = \OC::$server->get(ITemplateManager::class);
222
+            $templateManager->initializeTemplateDirectory(null, $userId);
223
+        }
224
+    }
225
+
226
+    /**
227
+     * copies a directory recursively by using streams
228
+     *
229
+     * @param string $source
230
+     * @param \OCP\Files\Folder $target
231
+     * @return void
232
+     */
233
+    public static function copyr($source, \OCP\Files\Folder $target) {
234
+        $logger = \OC::$server->getLogger();
235
+
236
+        // Verify if folder exists
237
+        $dir = opendir($source);
238
+        if ($dir === false) {
239
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
240
+            return;
241
+        }
242
+
243
+        // Copy the files
244
+        while (false !== ($file = readdir($dir))) {
245
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
246
+                if (is_dir($source . '/' . $file)) {
247
+                    $child = $target->newFolder($file);
248
+                    self::copyr($source . '/' . $file, $child);
249
+                } else {
250
+                    $child = $target->newFile($file);
251
+                    $sourceStream = fopen($source . '/' . $file, 'r');
252
+                    if ($sourceStream === false) {
253
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
254
+                        closedir($dir);
255
+                        return;
256
+                    }
257
+                    stream_copy_to_stream($sourceStream, $child->fopen('w'));
258
+                }
259
+            }
260
+        }
261
+        closedir($dir);
262
+    }
263
+
264
+    /**
265
+     * @return void
266
+     * @suppress PhanUndeclaredMethod
267
+     */
268
+    public static function tearDownFS() {
269
+        /** @var SetupManager $setupManager */
270
+        $setupManager = \OC::$server->get(SetupManager::class);
271
+        $setupManager->tearDown();
272
+    }
273
+
274
+    /**
275
+     * get the current installed version of ownCloud
276
+     *
277
+     * @return array
278
+     */
279
+    public static function getVersion() {
280
+        OC_Util::loadVersion();
281
+        return self::$versionCache['OC_Version'];
282
+    }
283
+
284
+    /**
285
+     * get the current installed version string of ownCloud
286
+     *
287
+     * @return string
288
+     */
289
+    public static function getVersionString() {
290
+        OC_Util::loadVersion();
291
+        return self::$versionCache['OC_VersionString'];
292
+    }
293
+
294
+    /**
295
+     * @deprecated the value is of no use anymore
296
+     * @return string
297
+     */
298
+    public static function getEditionString() {
299
+        return '';
300
+    }
301
+
302
+    /**
303
+     * @description get the update channel of the current installed of ownCloud.
304
+     * @return string
305
+     */
306
+    public static function getChannel() {
307
+        OC_Util::loadVersion();
308
+        return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
309
+    }
310
+
311
+    /**
312
+     * @description get the build number of the current installed of ownCloud.
313
+     * @return string
314
+     */
315
+    public static function getBuild() {
316
+        OC_Util::loadVersion();
317
+        return self::$versionCache['OC_Build'];
318
+    }
319
+
320
+    /**
321
+     * @description load the version.php into the session as cache
322
+     * @suppress PhanUndeclaredVariable
323
+     */
324
+    private static function loadVersion() {
325
+        if (self::$versionCache !== null) {
326
+            return;
327
+        }
328
+
329
+        $timestamp = filemtime(OC::$SERVERROOT . '/version.php');
330
+        require OC::$SERVERROOT . '/version.php';
331
+        /** @var int $timestamp */
332
+        self::$versionCache['OC_Version_Timestamp'] = $timestamp;
333
+        /** @var string $OC_Version */
334
+        self::$versionCache['OC_Version'] = $OC_Version;
335
+        /** @var string $OC_VersionString */
336
+        self::$versionCache['OC_VersionString'] = $OC_VersionString;
337
+        /** @var string $OC_Build */
338
+        self::$versionCache['OC_Build'] = $OC_Build;
339
+
340
+        /** @var string $OC_Channel */
341
+        self::$versionCache['OC_Channel'] = $OC_Channel;
342
+    }
343
+
344
+    /**
345
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
346
+     *
347
+     * @param string $application application to get the files from
348
+     * @param string $directory directory within this application (css, js, vendor, etc)
349
+     * @param string $file the file inside of the above folder
350
+     * @return string the path
351
+     */
352
+    private static function generatePath($application, $directory, $file) {
353
+        if (is_null($file)) {
354
+            $file = $application;
355
+            $application = "";
356
+        }
357
+        if (!empty($application)) {
358
+            return "$application/$directory/$file";
359
+        } else {
360
+            return "$directory/$file";
361
+        }
362
+    }
363
+
364
+    /**
365
+     * add a javascript file
366
+     *
367
+     * @deprecated 24.0.0 - Use \OCP\Util::addScript
368
+     *
369
+     * @param string $application application id
370
+     * @param string|null $file filename
371
+     * @param bool $prepend prepend the Script to the beginning of the list
372
+     * @return void
373
+     */
374
+    public static function addScript($application, $file = null, $prepend = false) {
375
+        $path = OC_Util::generatePath($application, 'js', $file);
376
+
377
+        // core js files need separate handling
378
+        if ($application !== 'core' && $file !== null) {
379
+            self::addTranslations($application);
380
+        }
381
+        self::addExternalResource($application, $prepend, $path, "script");
382
+    }
383
+
384
+    /**
385
+     * add a javascript file from the vendor sub folder
386
+     *
387
+     * @param string $application application id
388
+     * @param string|null $file filename
389
+     * @param bool $prepend prepend the Script to the beginning of the list
390
+     * @return void
391
+     */
392
+    public static function addVendorScript($application, $file = null, $prepend = false) {
393
+        $path = OC_Util::generatePath($application, 'vendor', $file);
394
+        self::addExternalResource($application, $prepend, $path, "script");
395
+    }
396
+
397
+    /**
398
+     * add a translation JS file
399
+     *
400
+     * @deprecated 24.0.0
401
+     *
402
+     * @param string $application application id
403
+     * @param string|null $languageCode language code, defaults to the current language
404
+     * @param bool|null $prepend prepend the Script to the beginning of the list
405
+     */
406
+    public static function addTranslations($application, $languageCode = null, $prepend = false) {
407
+        if (is_null($languageCode)) {
408
+            $languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
409
+        }
410
+        if (!empty($application)) {
411
+            $path = "$application/l10n/$languageCode";
412
+        } else {
413
+            $path = "l10n/$languageCode";
414
+        }
415
+        self::addExternalResource($application, $prepend, $path, "script");
416
+    }
417
+
418
+    /**
419
+     * add a css file
420
+     *
421
+     * @param string $application application id
422
+     * @param string|null $file filename
423
+     * @param bool $prepend prepend the Style to the beginning of the list
424
+     * @return void
425
+     */
426
+    public static function addStyle($application, $file = null, $prepend = false) {
427
+        $path = OC_Util::generatePath($application, 'css', $file);
428
+        self::addExternalResource($application, $prepend, $path, "style");
429
+    }
430
+
431
+    /**
432
+     * add a css file from the vendor sub folder
433
+     *
434
+     * @param string $application application id
435
+     * @param string|null $file filename
436
+     * @param bool $prepend prepend the Style to the beginning of the list
437
+     * @return void
438
+     */
439
+    public static function addVendorStyle($application, $file = null, $prepend = false) {
440
+        $path = OC_Util::generatePath($application, 'vendor', $file);
441
+        self::addExternalResource($application, $prepend, $path, "style");
442
+    }
443
+
444
+    /**
445
+     * add an external resource css/js file
446
+     *
447
+     * @param string $application application id
448
+     * @param bool $prepend prepend the file to the beginning of the list
449
+     * @param string $path
450
+     * @param string $type (script or style)
451
+     * @return void
452
+     */
453
+    private static function addExternalResource($application, $prepend, $path, $type = "script") {
454
+        if ($type === "style") {
455
+            if (!in_array($path, self::$styles)) {
456
+                if ($prepend === true) {
457
+                    array_unshift(self::$styles, $path);
458
+                } else {
459
+                    self::$styles[] = $path;
460
+                }
461
+            }
462
+        } elseif ($type === "script") {
463
+            if (!in_array($path, self::$scripts)) {
464
+                if ($prepend === true) {
465
+                    array_unshift(self::$scripts, $path);
466
+                } else {
467
+                    self::$scripts [] = $path;
468
+                }
469
+            }
470
+        }
471
+    }
472
+
473
+    /**
474
+     * Add a custom element to the header
475
+     * If $text is null then the element will be written as empty element.
476
+     * So use "" to get a closing tag.
477
+     * @param string $tag tag name of the element
478
+     * @param array $attributes array of attributes for the element
479
+     * @param string $text the text content for the element
480
+     * @param bool $prepend prepend the header to the beginning of the list
481
+     */
482
+    public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
483
+        $header = [
484
+            'tag' => $tag,
485
+            'attributes' => $attributes,
486
+            'text' => $text
487
+        ];
488
+        if ($prepend === true) {
489
+            array_unshift(self::$headers, $header);
490
+        } else {
491
+            self::$headers[] = $header;
492
+        }
493
+    }
494
+
495
+    /**
496
+     * check if the current server configuration is suitable for ownCloud
497
+     *
498
+     * @param \OC\SystemConfig $config
499
+     * @return array arrays with error messages and hints
500
+     */
501
+    public static function checkServer(\OC\SystemConfig $config) {
502
+        $l = \OC::$server->getL10N('lib');
503
+        $errors = [];
504
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
505
+
506
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
507
+            // this check needs to be done every time
508
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
509
+        }
510
+
511
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
512
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
513
+            return $errors;
514
+        }
515
+
516
+        $webServerRestart = false;
517
+        $setup = new \OC\Setup(
518
+            $config,
519
+            \OC::$server->get(IniGetWrapper::class),
520
+            \OC::$server->getL10N('lib'),
521
+            \OC::$server->get(\OCP\Defaults::class),
522
+            \OC::$server->get(LoggerInterface::class),
523
+            \OC::$server->getSecureRandom(),
524
+            \OC::$server->get(\OC\Installer::class)
525
+        );
526
+
527
+        $urlGenerator = \OC::$server->getURLGenerator();
528
+
529
+        $availableDatabases = $setup->getSupportedDatabases();
530
+        if (empty($availableDatabases)) {
531
+            $errors[] = [
532
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
533
+                'hint' => '' //TODO: sane hint
534
+            ];
535
+            $webServerRestart = true;
536
+        }
537
+
538
+        // Check if config folder is writable.
539
+        if (!OC_Helper::isReadOnlyConfigEnabled()) {
540
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
541
+                $errors[] = [
542
+                    'error' => $l->t('Cannot write into "config" directory.'),
543
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
544
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
545
+                        . $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',
546
+                        [ $urlGenerator->linkToDocs('admin-config') ])
547
+                ];
548
+            }
549
+        }
550
+
551
+        // Check if there is a writable install folder.
552
+        if ($config->getValue('appstoreenabled', true)) {
553
+            if (OC_App::getInstallPath() === null
554
+                || !is_writable(OC_App::getInstallPath())
555
+                || !is_readable(OC_App::getInstallPath())
556
+            ) {
557
+                $errors[] = [
558
+                    'error' => $l->t('Cannot write into "apps" directory.'),
559
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
560
+                        . ' or disabling the App Store in the config file.')
561
+                ];
562
+            }
563
+        }
564
+        // Create root dir.
565
+        if ($config->getValue('installed', false)) {
566
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
567
+                $success = @mkdir($CONFIG_DATADIRECTORY);
568
+                if ($success) {
569
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
570
+                } else {
571
+                    $errors[] = [
572
+                        'error' => $l->t('Cannot create "data" directory.'),
573
+                        'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
574
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
575
+                    ];
576
+                }
577
+            } elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
578
+                // is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
579
+                $testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
580
+                $handle = fopen($testFile, 'w');
581
+                if (!$handle || fwrite($handle, 'Test write operation') === false) {
582
+                    $permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
583
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')]);
584
+                    $errors[] = [
585
+                        'error' => $l->t('Your data directory is not writable.'),
586
+                        'hint' => $permissionsHint
587
+                    ];
588
+                } else {
589
+                    fclose($handle);
590
+                    unlink($testFile);
591
+                }
592
+            } else {
593
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
594
+            }
595
+        }
596
+
597
+        if (!OC_Util::isSetLocaleWorking()) {
598
+            $errors[] = [
599
+                'error' => $l->t('Setting locale to %s failed.',
600
+                    ['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
601
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
602
+                'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
603
+            ];
604
+        }
605
+
606
+        // Contains the dependencies that should be checked against
607
+        // classes = class_exists
608
+        // functions = function_exists
609
+        // defined = defined
610
+        // ini = ini_get
611
+        // If the dependency is not found the missing module name is shown to the EndUser
612
+        // When adding new checks always verify that they pass on Travis as well
613
+        // for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
614
+        $dependencies = [
615
+            'classes' => [
616
+                'ZipArchive' => 'zip',
617
+                'DOMDocument' => 'dom',
618
+                'XMLWriter' => 'XMLWriter',
619
+                'XMLReader' => 'XMLReader',
620
+            ],
621
+            'functions' => [
622
+                'xml_parser_create' => 'libxml',
623
+                'mb_strcut' => 'mbstring',
624
+                'ctype_digit' => 'ctype',
625
+                'json_encode' => 'JSON',
626
+                'gd_info' => 'GD',
627
+                'gzencode' => 'zlib',
628
+                'simplexml_load_string' => 'SimpleXML',
629
+                'hash' => 'HASH Message Digest Framework',
630
+                'curl_init' => 'cURL',
631
+                'openssl_verify' => 'OpenSSL',
632
+            ],
633
+            'defined' => [
634
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
635
+            ],
636
+            'ini' => [
637
+                'default_charset' => 'UTF-8',
638
+            ],
639
+        ];
640
+        $missingDependencies = [];
641
+        $invalidIniSettings = [];
642
+
643
+        $iniWrapper = \OC::$server->get(IniGetWrapper::class);
644
+        foreach ($dependencies['classes'] as $class => $module) {
645
+            if (!class_exists($class)) {
646
+                $missingDependencies[] = $module;
647
+            }
648
+        }
649
+        foreach ($dependencies['functions'] as $function => $module) {
650
+            if (!function_exists($function)) {
651
+                $missingDependencies[] = $module;
652
+            }
653
+        }
654
+        foreach ($dependencies['defined'] as $defined => $module) {
655
+            if (!defined($defined)) {
656
+                $missingDependencies[] = $module;
657
+            }
658
+        }
659
+        foreach ($dependencies['ini'] as $setting => $expected) {
660
+            if (is_bool($expected)) {
661
+                if ($iniWrapper->getBool($setting) !== $expected) {
662
+                    $invalidIniSettings[] = [$setting, $expected];
663
+                }
664
+            }
665
+            if (is_int($expected)) {
666
+                if ($iniWrapper->getNumeric($setting) !== $expected) {
667
+                    $invalidIniSettings[] = [$setting, $expected];
668
+                }
669
+            }
670
+            if (is_string($expected)) {
671
+                if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
672
+                    $invalidIniSettings[] = [$setting, $expected];
673
+                }
674
+            }
675
+        }
676
+
677
+        foreach ($missingDependencies as $missingDependency) {
678
+            $errors[] = [
679
+                'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
680
+                'hint' => $l->t('Please ask your server administrator to install the module.'),
681
+            ];
682
+            $webServerRestart = true;
683
+        }
684
+        foreach ($invalidIniSettings as $setting) {
685
+            if (is_bool($setting[1])) {
686
+                $setting[1] = $setting[1] ? 'on' : 'off';
687
+            }
688
+            $errors[] = [
689
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
690
+                'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
691
+            ];
692
+            $webServerRestart = true;
693
+        }
694
+
695
+        /**
696
+         * The mbstring.func_overload check can only be performed if the mbstring
697
+         * module is installed as it will return null if the checking setting is
698
+         * not available and thus a check on the boolean value fails.
699
+         *
700
+         * TODO: Should probably be implemented in the above generic dependency
701
+         *       check somehow in the long-term.
702
+         */
703
+        if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
704
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
705
+            $errors[] = [
706
+                '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')]),
707
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
708
+            ];
709
+        }
710
+
711
+        if (function_exists('xml_parser_create') &&
712
+            LIBXML_LOADED_VERSION < 20700) {
713
+            $version = LIBXML_LOADED_VERSION;
714
+            $major = floor($version / 10000);
715
+            $version -= ($major * 10000);
716
+            $minor = floor($version / 100);
717
+            $version -= ($minor * 100);
718
+            $patch = $version;
719
+            $errors[] = [
720
+                'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
721
+                'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
722
+            ];
723
+        }
724
+
725
+        if (!self::isAnnotationsWorking()) {
726
+            $errors[] = [
727
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
728
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
729
+            ];
730
+        }
731
+
732
+        if (!\OC::$CLI && $webServerRestart) {
733
+            $errors[] = [
734
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
735
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
736
+            ];
737
+        }
738
+
739
+        foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
740
+            if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
741
+                $errors[] = [
742
+                    'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
743
+                    'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
744
+                ];
745
+            }
746
+        }
747
+
748
+        $errors = array_merge($errors, self::checkDatabaseVersion());
749
+
750
+        // Cache the result of this function
751
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
752
+
753
+        return $errors;
754
+    }
755
+
756
+    /**
757
+     * Check the database version
758
+     *
759
+     * @return array errors array
760
+     */
761
+    public static function checkDatabaseVersion() {
762
+        $l = \OC::$server->getL10N('lib');
763
+        $errors = [];
764
+        $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
765
+        if ($dbType === 'pgsql') {
766
+            // check PostgreSQL version
767
+            try {
768
+                $result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
769
+                $data = $result->fetchRow();
770
+                $result->closeCursor();
771
+                if (isset($data['server_version'])) {
772
+                    $version = $data['server_version'];
773
+                    if (version_compare($version, '9.0.0', '<')) {
774
+                        $errors[] = [
775
+                            'error' => $l->t('PostgreSQL >= 9 required.'),
776
+                            'hint' => $l->t('Please upgrade your database version.')
777
+                        ];
778
+                    }
779
+                }
780
+            } catch (\Doctrine\DBAL\Exception $e) {
781
+                $logger = \OC::$server->getLogger();
782
+                $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
783
+                $logger->logException($e);
784
+            }
785
+        }
786
+        return $errors;
787
+    }
788
+
789
+    /**
790
+     * Check for correct file permissions of data directory
791
+     *
792
+     * @param string $dataDirectory
793
+     * @return array arrays with error messages and hints
794
+     */
795
+    public static function checkDataDirectoryPermissions($dataDirectory) {
796
+        if (\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
797
+            return  [];
798
+        }
799
+
800
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
801
+        if (substr($perms, -1) !== '0') {
802
+            chmod($dataDirectory, 0770);
803
+            clearstatcache();
804
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
805
+            if ($perms[2] !== '0') {
806
+                $l = \OC::$server->getL10N('lib');
807
+                return [[
808
+                    'error' => $l->t('Your data directory is readable by other users.'),
809
+                    'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'),
810
+                ]];
811
+            }
812
+        }
813
+        return [];
814
+    }
815
+
816
+    /**
817
+     * Check that the data directory exists and is valid by
818
+     * checking the existence of the ".ocdata" file.
819
+     *
820
+     * @param string $dataDirectory data directory path
821
+     * @return array errors found
822
+     */
823
+    public static function checkDataDirectoryValidity($dataDirectory) {
824
+        $l = \OC::$server->getL10N('lib');
825
+        $errors = [];
826
+        if ($dataDirectory[0] !== '/') {
827
+            $errors[] = [
828
+                'error' => $l->t('Your data directory must be an absolute path.'),
829
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
830
+            ];
831
+        }
832
+        if (!file_exists($dataDirectory . '/.ocdata')) {
833
+            $errors[] = [
834
+                'error' => $l->t('Your data directory is invalid.'),
835
+                'hint' => $l->t('Ensure there is a file called ".ocdata"' .
836
+                    ' in the root of the data directory.')
837
+            ];
838
+        }
839
+        return $errors;
840
+    }
841
+
842
+    /**
843
+     * Check if the user is logged in, redirects to home if not. With
844
+     * redirect URL parameter to the request URI.
845
+     *
846
+     * @return void
847
+     */
848
+    public static function checkLoggedIn() {
849
+        // Check if we are a user
850
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
851
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
852
+                        'core.login.showLoginForm',
853
+                        [
854
+                            'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
855
+                        ]
856
+                    )
857
+            );
858
+            exit();
859
+        }
860
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
861
+        if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
862
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
863
+            exit();
864
+        }
865
+    }
866
+
867
+    /**
868
+     * Check if the user is a admin, redirects to home if not
869
+     *
870
+     * @return void
871
+     */
872
+    public static function checkAdminUser() {
873
+        OC_Util::checkLoggedIn();
874
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
875
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
876
+            exit();
877
+        }
878
+    }
879
+
880
+    /**
881
+     * Returns the URL of the default page
882
+     * based on the system configuration and
883
+     * the apps visible for the current user
884
+     *
885
+     * @return string URL
886
+     * @suppress PhanDeprecatedFunction
887
+     */
888
+    public static function getDefaultPageUrl() {
889
+        /** @var IURLGenerator $urlGenerator */
890
+        $urlGenerator = \OC::$server->get(IURLGenerator::class);
891
+        return $urlGenerator->linkToDefaultPageUrl();
892
+    }
893
+
894
+    /**
895
+     * Redirect to the user default page
896
+     *
897
+     * @return void
898
+     */
899
+    public static function redirectToDefaultPage() {
900
+        $location = self::getDefaultPageUrl();
901
+        header('Location: ' . $location);
902
+        exit();
903
+    }
904
+
905
+    /**
906
+     * get an id unique for this instance
907
+     *
908
+     * @return string
909
+     */
910
+    public static function getInstanceId() {
911
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
912
+        if (is_null($id)) {
913
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
914
+            $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
915
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
916
+        }
917
+        return $id;
918
+    }
919
+
920
+    /**
921
+     * Public function to sanitize HTML
922
+     *
923
+     * This function is used to sanitize HTML and should be applied on any
924
+     * string or array of strings before displaying it on a web page.
925
+     *
926
+     * @param string|string[] $value
927
+     * @return string|string[] an array of sanitized strings or a single sanitized string, depends on the input parameter.
928
+     */
929
+    public static function sanitizeHTML($value) {
930
+        if (is_array($value)) {
931
+            /** @var string[] $value */
932
+            $value = array_map(function ($value) {
933
+                return self::sanitizeHTML($value);
934
+            }, $value);
935
+        } else {
936
+            // Specify encoding for PHP<5.4
937
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
938
+        }
939
+        return $value;
940
+    }
941
+
942
+    /**
943
+     * Public function to encode url parameters
944
+     *
945
+     * This function is used to encode path to file before output.
946
+     * Encoding is done according to RFC 3986 with one exception:
947
+     * Character '/' is preserved as is.
948
+     *
949
+     * @param string $component part of URI to encode
950
+     * @return string
951
+     */
952
+    public static function encodePath($component) {
953
+        $encoded = rawurlencode($component);
954
+        $encoded = str_replace('%2F', '/', $encoded);
955
+        return $encoded;
956
+    }
957
+
958
+
959
+    public function createHtaccessTestFile(\OCP\IConfig $config) {
960
+        // php dev server does not support htaccess
961
+        if (php_sapi_name() === 'cli-server') {
962
+            return false;
963
+        }
964
+
965
+        // testdata
966
+        $fileName = '/htaccesstest.txt';
967
+        $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
968
+
969
+        // creating a test file
970
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
971
+
972
+        if (file_exists($testFile)) {// already running this test, possible recursive call
973
+            return false;
974
+        }
975
+
976
+        $fp = @fopen($testFile, 'w');
977
+        if (!$fp) {
978
+            throw new \OCP\HintException('Can\'t create test file to check for working .htaccess file.',
979
+                'Make sure it is possible for the web server to write to ' . $testFile);
980
+        }
981
+        fwrite($fp, $testContent);
982
+        fclose($fp);
983
+
984
+        return $testContent;
985
+    }
986
+
987
+    /**
988
+     * Check if the .htaccess file is working
989
+     *
990
+     * @param \OCP\IConfig $config
991
+     * @return bool
992
+     * @throws Exception
993
+     * @throws \OCP\HintException If the test file can't get written.
994
+     */
995
+    public function isHtaccessWorking(\OCP\IConfig $config) {
996
+        if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
997
+            return true;
998
+        }
999
+
1000
+        $testContent = $this->createHtaccessTestFile($config);
1001
+        if ($testContent === false) {
1002
+            return false;
1003
+        }
1004
+
1005
+        $fileName = '/htaccesstest.txt';
1006
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1007
+
1008
+        // accessing the file via http
1009
+        $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1010
+        try {
1011
+            $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1012
+        } catch (\Exception $e) {
1013
+            $content = false;
1014
+        }
1015
+
1016
+        if (strpos($url, 'https:') === 0) {
1017
+            $url = 'http:' . substr($url, 6);
1018
+        } else {
1019
+            $url = 'https:' . substr($url, 5);
1020
+        }
1021
+
1022
+        try {
1023
+            $fallbackContent = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1024
+        } catch (\Exception $e) {
1025
+            $fallbackContent = false;
1026
+        }
1027
+
1028
+        // cleanup
1029
+        @unlink($testFile);
1030
+
1031
+        /*
1032 1032
 		 * If the content is not equal to test content our .htaccess
1033 1033
 		 * is working as required
1034 1034
 		 */
1035
-		return $content !== $testContent && $fallbackContent !== $testContent;
1036
-	}
1037
-
1038
-	/**
1039
-	 * Check if current locale is non-UTF8
1040
-	 *
1041
-	 * @return bool
1042
-	 */
1043
-	private static function isNonUTF8Locale() {
1044
-		if (function_exists('escapeshellcmd')) {
1045
-			return '' === escapeshellcmd('§');
1046
-		} elseif (function_exists('escapeshellarg')) {
1047
-			return '\'\'' === escapeshellarg('§');
1048
-		} else {
1049
-			return 0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0));
1050
-		}
1051
-	}
1052
-
1053
-	/**
1054
-	 * Check if the setlocale call does not work. This can happen if the right
1055
-	 * local packages are not available on the server.
1056
-	 *
1057
-	 * @return bool
1058
-	 */
1059
-	public static function isSetLocaleWorking() {
1060
-		if (self::isNonUTF8Locale()) {
1061
-			// Borrowed from \Patchwork\Utf8\Bootup::initLocale
1062
-			setlocale(LC_ALL, 'C.UTF-8', 'C');
1063
-			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');
1064
-
1065
-			// Check again
1066
-			if (self::isNonUTF8Locale()) {
1067
-				return false;
1068
-			}
1069
-		}
1070
-
1071
-		return true;
1072
-	}
1073
-
1074
-	/**
1075
-	 * Check if it's possible to get the inline annotations
1076
-	 *
1077
-	 * @return bool
1078
-	 */
1079
-	public static function isAnnotationsWorking() {
1080
-		$reflection = new \ReflectionMethod(__METHOD__);
1081
-		$docs = $reflection->getDocComment();
1082
-
1083
-		return (is_string($docs) && strlen($docs) > 50);
1084
-	}
1085
-
1086
-	/**
1087
-	 * Check if the PHP module fileinfo is loaded.
1088
-	 *
1089
-	 * @return bool
1090
-	 */
1091
-	public static function fileInfoLoaded() {
1092
-		return function_exists('finfo_open');
1093
-	}
1094
-
1095
-	/**
1096
-	 * clear all levels of output buffering
1097
-	 *
1098
-	 * @return void
1099
-	 */
1100
-	public static function obEnd() {
1101
-		while (ob_get_level()) {
1102
-			ob_end_clean();
1103
-		}
1104
-	}
1105
-
1106
-	/**
1107
-	 * Checks whether the server is running on Mac OS X
1108
-	 *
1109
-	 * @return bool true if running on Mac OS X, false otherwise
1110
-	 */
1111
-	public static function runningOnMac() {
1112
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1113
-	}
1114
-
1115
-	/**
1116
-	 * Handles the case that there may not be a theme, then check if a "default"
1117
-	 * theme exists and take that one
1118
-	 *
1119
-	 * @return string the theme
1120
-	 */
1121
-	public static function getTheme() {
1122
-		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1123
-
1124
-		if ($theme === '') {
1125
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1126
-				$theme = 'default';
1127
-			}
1128
-		}
1129
-
1130
-		return $theme;
1131
-	}
1132
-
1133
-	/**
1134
-	 * Normalize a unicode string
1135
-	 *
1136
-	 * @param string $value a not normalized string
1137
-	 * @return bool|string
1138
-	 */
1139
-	public static function normalizeUnicode($value) {
1140
-		if (Normalizer::isNormalized($value)) {
1141
-			return $value;
1142
-		}
1143
-
1144
-		$normalizedValue = Normalizer::normalize($value);
1145
-		if ($normalizedValue === null || $normalizedValue === false) {
1146
-			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1147
-			return $value;
1148
-		}
1149
-
1150
-		return $normalizedValue;
1151
-	}
1152
-
1153
-	/**
1154
-	 * A human readable string is generated based on version and build number
1155
-	 *
1156
-	 * @return string
1157
-	 */
1158
-	public static function getHumanVersion() {
1159
-		$version = OC_Util::getVersionString();
1160
-		$build = OC_Util::getBuild();
1161
-		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1162
-			$version .= ' Build:' . $build;
1163
-		}
1164
-		return $version;
1165
-	}
1166
-
1167
-	/**
1168
-	 * Returns whether the given file name is valid
1169
-	 *
1170
-	 * @param string $file file name to check
1171
-	 * @return bool true if the file name is valid, false otherwise
1172
-	 * @deprecated use \OC\Files\View::verifyPath()
1173
-	 */
1174
-	public static function isValidFileName($file) {
1175
-		$trimmed = trim($file);
1176
-		if ($trimmed === '') {
1177
-			return false;
1178
-		}
1179
-		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1180
-			return false;
1181
-		}
1182
-
1183
-		// detect part files
1184
-		if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1185
-			return false;
1186
-		}
1187
-
1188
-		foreach (str_split($trimmed) as $char) {
1189
-			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1190
-				return false;
1191
-			}
1192
-		}
1193
-		return true;
1194
-	}
1195
-
1196
-	/**
1197
-	 * Check whether the instance needs to perform an upgrade,
1198
-	 * either when the core version is higher or any app requires
1199
-	 * an upgrade.
1200
-	 *
1201
-	 * @param \OC\SystemConfig $config
1202
-	 * @return bool whether the core or any app needs an upgrade
1203
-	 * @throws \OCP\HintException When the upgrade from the given version is not allowed
1204
-	 */
1205
-	public static function needUpgrade(\OC\SystemConfig $config) {
1206
-		if ($config->getValue('installed', false)) {
1207
-			$installedVersion = $config->getValue('version', '0.0.0');
1208
-			$currentVersion = implode('.', \OCP\Util::getVersion());
1209
-			$versionDiff = version_compare($currentVersion, $installedVersion);
1210
-			if ($versionDiff > 0) {
1211
-				return true;
1212
-			} elseif ($config->getValue('debug', false) && $versionDiff < 0) {
1213
-				// downgrade with debug
1214
-				$installedMajor = explode('.', $installedVersion);
1215
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1216
-				$currentMajor = explode('.', $currentVersion);
1217
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1218
-				if ($installedMajor === $currentMajor) {
1219
-					// Same major, allow downgrade for developers
1220
-					return true;
1221
-				} else {
1222
-					// downgrade attempt, throw exception
1223
-					throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1224
-				}
1225
-			} elseif ($versionDiff < 0) {
1226
-				// downgrade attempt, throw exception
1227
-				throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1228
-			}
1229
-
1230
-			// also check for upgrades for apps (independently from the user)
1231
-			$apps = \OC_App::getEnabledApps(false, true);
1232
-			$shouldUpgrade = false;
1233
-			foreach ($apps as $app) {
1234
-				if (\OC_App::shouldUpgrade($app)) {
1235
-					$shouldUpgrade = true;
1236
-					break;
1237
-				}
1238
-			}
1239
-			return $shouldUpgrade;
1240
-		} else {
1241
-			return false;
1242
-		}
1243
-	}
1035
+        return $content !== $testContent && $fallbackContent !== $testContent;
1036
+    }
1037
+
1038
+    /**
1039
+     * Check if current locale is non-UTF8
1040
+     *
1041
+     * @return bool
1042
+     */
1043
+    private static function isNonUTF8Locale() {
1044
+        if (function_exists('escapeshellcmd')) {
1045
+            return '' === escapeshellcmd('§');
1046
+        } elseif (function_exists('escapeshellarg')) {
1047
+            return '\'\'' === escapeshellarg('§');
1048
+        } else {
1049
+            return 0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0));
1050
+        }
1051
+    }
1052
+
1053
+    /**
1054
+     * Check if the setlocale call does not work. This can happen if the right
1055
+     * local packages are not available on the server.
1056
+     *
1057
+     * @return bool
1058
+     */
1059
+    public static function isSetLocaleWorking() {
1060
+        if (self::isNonUTF8Locale()) {
1061
+            // Borrowed from \Patchwork\Utf8\Bootup::initLocale
1062
+            setlocale(LC_ALL, 'C.UTF-8', 'C');
1063
+            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');
1064
+
1065
+            // Check again
1066
+            if (self::isNonUTF8Locale()) {
1067
+                return false;
1068
+            }
1069
+        }
1070
+
1071
+        return true;
1072
+    }
1073
+
1074
+    /**
1075
+     * Check if it's possible to get the inline annotations
1076
+     *
1077
+     * @return bool
1078
+     */
1079
+    public static function isAnnotationsWorking() {
1080
+        $reflection = new \ReflectionMethod(__METHOD__);
1081
+        $docs = $reflection->getDocComment();
1082
+
1083
+        return (is_string($docs) && strlen($docs) > 50);
1084
+    }
1085
+
1086
+    /**
1087
+     * Check if the PHP module fileinfo is loaded.
1088
+     *
1089
+     * @return bool
1090
+     */
1091
+    public static function fileInfoLoaded() {
1092
+        return function_exists('finfo_open');
1093
+    }
1094
+
1095
+    /**
1096
+     * clear all levels of output buffering
1097
+     *
1098
+     * @return void
1099
+     */
1100
+    public static function obEnd() {
1101
+        while (ob_get_level()) {
1102
+            ob_end_clean();
1103
+        }
1104
+    }
1105
+
1106
+    /**
1107
+     * Checks whether the server is running on Mac OS X
1108
+     *
1109
+     * @return bool true if running on Mac OS X, false otherwise
1110
+     */
1111
+    public static function runningOnMac() {
1112
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1113
+    }
1114
+
1115
+    /**
1116
+     * Handles the case that there may not be a theme, then check if a "default"
1117
+     * theme exists and take that one
1118
+     *
1119
+     * @return string the theme
1120
+     */
1121
+    public static function getTheme() {
1122
+        $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1123
+
1124
+        if ($theme === '') {
1125
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1126
+                $theme = 'default';
1127
+            }
1128
+        }
1129
+
1130
+        return $theme;
1131
+    }
1132
+
1133
+    /**
1134
+     * Normalize a unicode string
1135
+     *
1136
+     * @param string $value a not normalized string
1137
+     * @return bool|string
1138
+     */
1139
+    public static function normalizeUnicode($value) {
1140
+        if (Normalizer::isNormalized($value)) {
1141
+            return $value;
1142
+        }
1143
+
1144
+        $normalizedValue = Normalizer::normalize($value);
1145
+        if ($normalizedValue === null || $normalizedValue === false) {
1146
+            \OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1147
+            return $value;
1148
+        }
1149
+
1150
+        return $normalizedValue;
1151
+    }
1152
+
1153
+    /**
1154
+     * A human readable string is generated based on version and build number
1155
+     *
1156
+     * @return string
1157
+     */
1158
+    public static function getHumanVersion() {
1159
+        $version = OC_Util::getVersionString();
1160
+        $build = OC_Util::getBuild();
1161
+        if (!empty($build) and OC_Util::getChannel() === 'daily') {
1162
+            $version .= ' Build:' . $build;
1163
+        }
1164
+        return $version;
1165
+    }
1166
+
1167
+    /**
1168
+     * Returns whether the given file name is valid
1169
+     *
1170
+     * @param string $file file name to check
1171
+     * @return bool true if the file name is valid, false otherwise
1172
+     * @deprecated use \OC\Files\View::verifyPath()
1173
+     */
1174
+    public static function isValidFileName($file) {
1175
+        $trimmed = trim($file);
1176
+        if ($trimmed === '') {
1177
+            return false;
1178
+        }
1179
+        if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1180
+            return false;
1181
+        }
1182
+
1183
+        // detect part files
1184
+        if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1185
+            return false;
1186
+        }
1187
+
1188
+        foreach (str_split($trimmed) as $char) {
1189
+            if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1190
+                return false;
1191
+            }
1192
+        }
1193
+        return true;
1194
+    }
1195
+
1196
+    /**
1197
+     * Check whether the instance needs to perform an upgrade,
1198
+     * either when the core version is higher or any app requires
1199
+     * an upgrade.
1200
+     *
1201
+     * @param \OC\SystemConfig $config
1202
+     * @return bool whether the core or any app needs an upgrade
1203
+     * @throws \OCP\HintException When the upgrade from the given version is not allowed
1204
+     */
1205
+    public static function needUpgrade(\OC\SystemConfig $config) {
1206
+        if ($config->getValue('installed', false)) {
1207
+            $installedVersion = $config->getValue('version', '0.0.0');
1208
+            $currentVersion = implode('.', \OCP\Util::getVersion());
1209
+            $versionDiff = version_compare($currentVersion, $installedVersion);
1210
+            if ($versionDiff > 0) {
1211
+                return true;
1212
+            } elseif ($config->getValue('debug', false) && $versionDiff < 0) {
1213
+                // downgrade with debug
1214
+                $installedMajor = explode('.', $installedVersion);
1215
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1216
+                $currentMajor = explode('.', $currentVersion);
1217
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1218
+                if ($installedMajor === $currentMajor) {
1219
+                    // Same major, allow downgrade for developers
1220
+                    return true;
1221
+                } else {
1222
+                    // downgrade attempt, throw exception
1223
+                    throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1224
+                }
1225
+            } elseif ($versionDiff < 0) {
1226
+                // downgrade attempt, throw exception
1227
+                throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1228
+            }
1229
+
1230
+            // also check for upgrades for apps (independently from the user)
1231
+            $apps = \OC_App::getEnabledApps(false, true);
1232
+            $shouldUpgrade = false;
1233
+            foreach ($apps as $app) {
1234
+                if (\OC_App::shouldUpgrade($app)) {
1235
+                    $shouldUpgrade = true;
1236
+                    break;
1237
+                }
1238
+            }
1239
+            return $shouldUpgrade;
1240
+        } else {
1241
+            return false;
1242
+        }
1243
+    }
1244 1244
 }
Please login to merge, or discard this patch.