Passed
Push — master ( dbd0cf...f323c5 )
by Blizzz
12:55 queued 12s
created
lib/base.php 1 patch
Indentation   +1048 added lines, -1048 removed lines patch added patch discarded remove patch
@@ -81,1054 +81,1054 @@
 block discarded – undo
81 81
  * OC_autoload!
82 82
  */
83 83
 class OC {
84
-	/**
85
-	 * Associative array for autoloading. classname => filename
86
-	 */
87
-	public static $CLASSPATH = [];
88
-	/**
89
-	 * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
90
-	 */
91
-	public static $SERVERROOT = '';
92
-	/**
93
-	 * the current request path relative to the Nextcloud root (e.g. files/index.php)
94
-	 */
95
-	private static $SUBURI = '';
96
-	/**
97
-	 * the Nextcloud root path for http requests (e.g. nextcloud/)
98
-	 */
99
-	public static $WEBROOT = '';
100
-	/**
101
-	 * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
102
-	 * web path in 'url'
103
-	 */
104
-	public static $APPSROOTS = [];
105
-
106
-	/**
107
-	 * @var string
108
-	 */
109
-	public static $configDir;
110
-
111
-	/**
112
-	 * requested app
113
-	 */
114
-	public static $REQUESTEDAPP = '';
115
-
116
-	/**
117
-	 * check if Nextcloud runs in cli mode
118
-	 */
119
-	public static $CLI = false;
120
-
121
-	/**
122
-	 * @var \OC\Autoloader $loader
123
-	 */
124
-	public static $loader = null;
125
-
126
-	/** @var \Composer\Autoload\ClassLoader $composerAutoloader */
127
-	public static $composerAutoloader = null;
128
-
129
-	/**
130
-	 * @var \OC\Server
131
-	 */
132
-	public static $server = null;
133
-
134
-	/**
135
-	 * @var \OC\Config
136
-	 */
137
-	private static $config = null;
138
-
139
-	/**
140
-	 * @throws \RuntimeException when the 3rdparty directory is missing or
141
-	 * the app path list is empty or contains an invalid path
142
-	 */
143
-	public static function initPaths() {
144
-		if (defined('PHPUNIT_CONFIG_DIR')) {
145
-			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
146
-		} elseif (defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
147
-			self::$configDir = OC::$SERVERROOT . '/tests/config/';
148
-		} elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
149
-			self::$configDir = rtrim($dir, '/') . '/';
150
-		} else {
151
-			self::$configDir = OC::$SERVERROOT . '/config/';
152
-		}
153
-		self::$config = new \OC\Config(self::$configDir);
154
-
155
-		OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
156
-		/**
157
-		 * FIXME: The following lines are required because we can't yet instantiate
158
-		 *        \OC::$server->getRequest() since \OC::$server does not yet exist.
159
-		 */
160
-		$params = [
161
-			'server' => [
162
-				'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
163
-				'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
164
-			],
165
-		];
166
-		$fakeRequest = new \OC\AppFramework\Http\Request(
167
-			$params,
168
-			new \OC\AppFramework\Http\RequestId($_SERVER['UNIQUE_ID'] ?? '', new \OC\Security\SecureRandom()),
169
-			new \OC\AllConfig(new \OC\SystemConfig(self::$config))
170
-		);
171
-		$scriptName = $fakeRequest->getScriptName();
172
-		if (substr($scriptName, -1) == '/') {
173
-			$scriptName .= 'index.php';
174
-			//make sure suburi follows the same rules as scriptName
175
-			if (substr(OC::$SUBURI, -9) != 'index.php') {
176
-				if (substr(OC::$SUBURI, -1) != '/') {
177
-					OC::$SUBURI = OC::$SUBURI . '/';
178
-				}
179
-				OC::$SUBURI = OC::$SUBURI . 'index.php';
180
-			}
181
-		}
182
-
183
-
184
-		if (OC::$CLI) {
185
-			OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
186
-		} else {
187
-			if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
188
-				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
189
-
190
-				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
191
-					OC::$WEBROOT = '/' . OC::$WEBROOT;
192
-				}
193
-			} else {
194
-				// The scriptName is not ending with OC::$SUBURI
195
-				// This most likely means that we are calling from CLI.
196
-				// However some cron jobs still need to generate
197
-				// a web URL, so we use overwritewebroot as a fallback.
198
-				OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
199
-			}
200
-
201
-			// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
202
-			// slash which is required by URL generation.
203
-			if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
204
-					substr($_SERVER['REQUEST_URI'], -1) !== '/') {
205
-				header('Location: '.\OC::$WEBROOT.'/');
206
-				exit();
207
-			}
208
-		}
209
-
210
-		// search the apps folder
211
-		$config_paths = self::$config->getValue('apps_paths', []);
212
-		if (!empty($config_paths)) {
213
-			foreach ($config_paths as $paths) {
214
-				if (isset($paths['url']) && isset($paths['path'])) {
215
-					$paths['url'] = rtrim($paths['url'], '/');
216
-					$paths['path'] = rtrim($paths['path'], '/');
217
-					OC::$APPSROOTS[] = $paths;
218
-				}
219
-			}
220
-		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
221
-			OC::$APPSROOTS[] = ['path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true];
222
-		}
223
-
224
-		if (empty(OC::$APPSROOTS)) {
225
-			throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
226
-				. '. You can also configure the location in the config.php file.');
227
-		}
228
-		$paths = [];
229
-		foreach (OC::$APPSROOTS as $path) {
230
-			$paths[] = $path['path'];
231
-			if (!is_dir($path['path'])) {
232
-				throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
233
-					. ' Nextcloud folder. You can also configure the location in the config.php file.', $path['path']));
234
-			}
235
-		}
236
-
237
-		// set the right include path
238
-		set_include_path(
239
-			implode(PATH_SEPARATOR, $paths)
240
-		);
241
-	}
242
-
243
-	public static function checkConfig() {
244
-		$l = \OC::$server->getL10N('lib');
245
-
246
-		// Create config if it does not already exist
247
-		$configFilePath = self::$configDir .'/config.php';
248
-		if (!file_exists($configFilePath)) {
249
-			@touch($configFilePath);
250
-		}
251
-
252
-		// Check if config is writable
253
-		$configFileWritable = is_writable($configFilePath);
254
-		if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
255
-			|| !$configFileWritable && \OCP\Util::needUpgrade()) {
256
-			$urlGenerator = \OC::$server->getURLGenerator();
257
-
258
-			if (self::$CLI) {
259
-				echo $l->t('Cannot write into "config" directory!')."\n";
260
-				echo $l->t('This can usually be fixed by giving the web server write access to the config directory.')."\n";
261
-				echo "\n";
262
-				echo $l->t('But, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it.')."\n";
263
-				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-config') ])."\n";
264
-				exit;
265
-			} else {
266
-				OC_Template::printErrorPage(
267
-					$l->t('Cannot write into "config" directory!'),
268
-					$l->t('This can usually be fixed by giving the web server write access to the config directory.') . ' '
269
-					. $l->t('But, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it.') . ' '
270
-					. $l->t('See %s', [ $urlGenerator->linkToDocs('admin-config') ]),
271
-					503
272
-				);
273
-			}
274
-		}
275
-	}
276
-
277
-	public static function checkInstalled(\OC\SystemConfig $systemConfig) {
278
-		if (defined('OC_CONSOLE')) {
279
-			return;
280
-		}
281
-		// Redirect to installer if not installed
282
-		if (!$systemConfig->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
283
-			if (OC::$CLI) {
284
-				throw new Exception('Not installed');
285
-			} else {
286
-				$url = OC::$WEBROOT . '/index.php';
287
-				header('Location: ' . $url);
288
-			}
289
-			exit();
290
-		}
291
-	}
292
-
293
-	public static function checkMaintenanceMode(\OC\SystemConfig $systemConfig) {
294
-		// Allow ajax update script to execute without being stopped
295
-		if (((bool) $systemConfig->getValue('maintenance', false)) && OC::$SUBURI != '/core/ajax/update.php') {
296
-			// send http status 503
297
-			http_response_code(503);
298
-			header('X-Nextcloud-Maintenance-Mode: 1');
299
-			header('Retry-After: 120');
300
-
301
-			// render error page
302
-			$template = new OC_Template('', 'update.user', 'guest');
303
-			\OCP\Util::addScript('core', 'maintenance');
304
-			\OCP\Util::addStyle('core', 'guest');
305
-			$template->printPage();
306
-			die();
307
-		}
308
-	}
309
-
310
-	/**
311
-	 * Prints the upgrade page
312
-	 *
313
-	 * @param \OC\SystemConfig $systemConfig
314
-	 */
315
-	private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
316
-		$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
317
-		$tooBig = false;
318
-		if (!$disableWebUpdater) {
319
-			$apps = \OC::$server->getAppManager();
320
-			if ($apps->isInstalled('user_ldap')) {
321
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
322
-
323
-				$result = $qb->select($qb->func()->count('*', 'user_count'))
324
-					->from('ldap_user_mapping')
325
-					->execute();
326
-				$row = $result->fetch();
327
-				$result->closeCursor();
328
-
329
-				$tooBig = ($row['user_count'] > 50);
330
-			}
331
-			if (!$tooBig && $apps->isInstalled('user_saml')) {
332
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
333
-
334
-				$result = $qb->select($qb->func()->count('*', 'user_count'))
335
-					->from('user_saml_users')
336
-					->execute();
337
-				$row = $result->fetch();
338
-				$result->closeCursor();
339
-
340
-				$tooBig = ($row['user_count'] > 50);
341
-			}
342
-			if (!$tooBig) {
343
-				// count users
344
-				$stats = \OC::$server->getUserManager()->countUsers();
345
-				$totalUsers = array_sum($stats);
346
-				$tooBig = ($totalUsers > 50);
347
-			}
348
-		}
349
-		$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
350
-			$_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
351
-
352
-		if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
353
-			// send http status 503
354
-			http_response_code(503);
355
-			header('Retry-After: 120');
356
-
357
-			// render error page
358
-			$template = new OC_Template('', 'update.use-cli', 'guest');
359
-			$template->assign('productName', 'nextcloud'); // for now
360
-			$template->assign('version', OC_Util::getVersionString());
361
-			$template->assign('tooBig', $tooBig);
362
-
363
-			$template->printPage();
364
-			die();
365
-		}
366
-
367
-		// check whether this is a core update or apps update
368
-		$installedVersion = $systemConfig->getValue('version', '0.0.0');
369
-		$currentVersion = implode('.', \OCP\Util::getVersion());
370
-
371
-		// if not a core upgrade, then it's apps upgrade
372
-		$isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
373
-
374
-		$oldTheme = $systemConfig->getValue('theme');
375
-		$systemConfig->setValue('theme', '');
376
-		\OCP\Util::addScript('core', 'common');
377
-		\OCP\Util::addScript('core', 'main');
378
-		\OCP\Util::addTranslations('core');
379
-		\OCP\Util::addScript('core', 'update');
380
-
381
-		/** @var \OC\App\AppManager $appManager */
382
-		$appManager = \OC::$server->getAppManager();
383
-
384
-		$tmpl = new OC_Template('', 'update.admin', 'guest');
385
-		$tmpl->assign('version', OC_Util::getVersionString());
386
-		$tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
387
-
388
-		// get third party apps
389
-		$ocVersion = \OCP\Util::getVersion();
390
-		$ocVersion = implode('.', $ocVersion);
391
-		$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
392
-		$incompatibleShippedApps = [];
393
-		foreach ($incompatibleApps as $appInfo) {
394
-			if ($appManager->isShipped($appInfo['id'])) {
395
-				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
396
-			}
397
-		}
398
-
399
-		if (!empty($incompatibleShippedApps)) {
400
-			$l = \OC::$server->getL10N('core');
401
-			$hint = $l->t('The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
402
-			throw new \OCP\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
403
-		}
404
-
405
-		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
406
-		$tmpl->assign('incompatibleAppsList', $incompatibleApps);
407
-		try {
408
-			$defaults = new \OC_Defaults();
409
-			$tmpl->assign('productName', $defaults->getName());
410
-		} catch (Throwable $error) {
411
-			$tmpl->assign('productName', 'Nextcloud');
412
-		}
413
-		$tmpl->assign('oldTheme', $oldTheme);
414
-		$tmpl->printPage();
415
-	}
416
-
417
-	public static function initSession() {
418
-		if (self::$server->getRequest()->getServerProtocol() === 'https') {
419
-			ini_set('session.cookie_secure', 'true');
420
-		}
421
-
422
-		// prevents javascript from accessing php session cookies
423
-		ini_set('session.cookie_httponly', 'true');
424
-
425
-		// set the cookie path to the Nextcloud directory
426
-		$cookie_path = OC::$WEBROOT ? : '/';
427
-		ini_set('session.cookie_path', $cookie_path);
428
-
429
-		// Let the session name be changed in the initSession Hook
430
-		$sessionName = OC_Util::getInstanceId();
431
-
432
-		try {
433
-			// set the session name to the instance id - which is unique
434
-			$session = new \OC\Session\Internal($sessionName);
435
-
436
-			$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
437
-			$session = $cryptoWrapper->wrapSession($session);
438
-			self::$server->setSession($session);
439
-
440
-			// if session can't be started break with http 500 error
441
-		} catch (Exception $e) {
442
-			\OC::$server->getLogger()->logException($e, ['app' => 'base']);
443
-			//show the user a detailed error page
444
-			OC_Template::printExceptionErrorPage($e, 500);
445
-			die();
446
-		}
447
-
448
-		//try to set the session lifetime
449
-		$sessionLifeTime = self::getSessionLifeTime();
450
-		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
451
-
452
-		// session timeout
453
-		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
454
-			if (isset($_COOKIE[session_name()])) {
455
-				setcookie(session_name(), '', -1, self::$WEBROOT ? : '/');
456
-			}
457
-			\OC::$server->getUserSession()->logout();
458
-		}
459
-
460
-		if (!self::hasSessionRelaxedExpiry()) {
461
-			$session->set('LAST_ACTIVITY', time());
462
-		}
463
-		$session->close();
464
-	}
465
-
466
-	/**
467
-	 * @return string
468
-	 */
469
-	private static function getSessionLifeTime() {
470
-		return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
471
-	}
472
-
473
-	/**
474
-	 * @return bool true if the session expiry should only be done by gc instead of an explicit timeout
475
-	 */
476
-	public static function hasSessionRelaxedExpiry(): bool {
477
-		return \OC::$server->getConfig()->getSystemValue('session_relaxed_expiry', false);
478
-	}
479
-
480
-	/**
481
-	 * Try to set some values to the required Nextcloud default
482
-	 */
483
-	public static function setRequiredIniValues() {
484
-		@ini_set('default_charset', 'UTF-8');
485
-		@ini_set('gd.jpeg_ignore_warning', '1');
486
-	}
487
-
488
-	/**
489
-	 * Send the same site cookies
490
-	 */
491
-	private static function sendSameSiteCookies() {
492
-		$cookieParams = session_get_cookie_params();
493
-		$secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
494
-		$policies = [
495
-			'lax',
496
-			'strict',
497
-		];
498
-
499
-		// Append __Host to the cookie if it meets the requirements
500
-		$cookiePrefix = '';
501
-		if ($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
502
-			$cookiePrefix = '__Host-';
503
-		}
504
-
505
-		foreach ($policies as $policy) {
506
-			header(
507
-				sprintf(
508
-					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
509
-					$cookiePrefix,
510
-					$policy,
511
-					$cookieParams['path'],
512
-					$policy
513
-				),
514
-				false
515
-			);
516
-		}
517
-	}
518
-
519
-	/**
520
-	 * Same Site cookie to further mitigate CSRF attacks. This cookie has to
521
-	 * be set in every request if cookies are sent to add a second level of
522
-	 * defense against CSRF.
523
-	 *
524
-	 * If the cookie is not sent this will set the cookie and reload the page.
525
-	 * We use an additional cookie since we want to protect logout CSRF and
526
-	 * also we can't directly interfere with PHP's session mechanism.
527
-	 */
528
-	private static function performSameSiteCookieProtection(\OCP\IConfig $config) {
529
-		$request = \OC::$server->getRequest();
530
-
531
-		// Some user agents are notorious and don't really properly follow HTTP
532
-		// specifications. For those, have an automated opt-out. Since the protection
533
-		// for remote.php is applied in base.php as starting point we need to opt out
534
-		// here.
535
-		$incompatibleUserAgents = $config->getSystemValue('csrf.optout');
536
-
537
-		// Fallback, if csrf.optout is unset
538
-		if (!is_array($incompatibleUserAgents)) {
539
-			$incompatibleUserAgents = [
540
-				// OS X Finder
541
-				'/^WebDAVFS/',
542
-				// Windows webdav drive
543
-				'/^Microsoft-WebDAV-MiniRedir/',
544
-			];
545
-		}
546
-
547
-		if ($request->isUserAgent($incompatibleUserAgents)) {
548
-			return;
549
-		}
550
-
551
-		if (count($_COOKIE) > 0) {
552
-			$requestUri = $request->getScriptName();
553
-			$processingScript = explode('/', $requestUri);
554
-			$processingScript = $processingScript[count($processingScript) - 1];
555
-
556
-			// index.php routes are handled in the middleware
557
-			if ($processingScript === 'index.php') {
558
-				return;
559
-			}
560
-
561
-			// All other endpoints require the lax and the strict cookie
562
-			if (!$request->passesStrictCookieCheck()) {
563
-				self::sendSameSiteCookies();
564
-				// Debug mode gets access to the resources without strict cookie
565
-				// due to the fact that the SabreDAV browser also lives there.
566
-				if (!$config->getSystemValue('debug', false)) {
567
-					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
568
-					exit();
569
-				}
570
-			}
571
-		} elseif (!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
572
-			self::sendSameSiteCookies();
573
-		}
574
-	}
575
-
576
-	public static function init() {
577
-		// calculate the root directories
578
-		OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
579
-
580
-		// register autoloader
581
-		$loaderStart = microtime(true);
582
-		require_once __DIR__ . '/autoloader.php';
583
-		self::$loader = new \OC\Autoloader([
584
-			OC::$SERVERROOT . '/lib/private/legacy',
585
-		]);
586
-		if (defined('PHPUNIT_RUN')) {
587
-			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
588
-		}
589
-		spl_autoload_register([self::$loader, 'load']);
590
-		$loaderEnd = microtime(true);
591
-
592
-		self::$CLI = (php_sapi_name() == 'cli');
593
-
594
-		// Add default composer PSR-4 autoloader
595
-		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
596
-
597
-		try {
598
-			self::initPaths();
599
-			// setup 3rdparty autoloader
600
-			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
601
-			if (!file_exists($vendorAutoLoad)) {
602
-				throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
603
-			}
604
-			require_once $vendorAutoLoad;
605
-		} catch (\RuntimeException $e) {
606
-			if (!self::$CLI) {
607
-				http_response_code(503);
608
-			}
609
-			// we can't use the template error page here, because this needs the
610
-			// DI container which isn't available yet
611
-			print($e->getMessage());
612
-			exit();
613
-		}
614
-
615
-		// setup the basic server
616
-		self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
617
-		self::$server->boot();
618
-
619
-		$eventLogger = \OC::$server->getEventLogger();
620
-		$eventLogger->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
621
-		$eventLogger->start('boot', 'Initialize');
622
-
623
-		// Override php.ini and log everything if we're troubleshooting
624
-		if (self::$config->getValue('loglevel') === ILogger::DEBUG) {
625
-			error_reporting(E_ALL);
626
-		}
627
-
628
-		// Don't display errors and log them
629
-		@ini_set('display_errors', '0');
630
-		@ini_set('log_errors', '1');
631
-
632
-		if (!date_default_timezone_set('UTC')) {
633
-			throw new \RuntimeException('Could not set timezone to UTC');
634
-		}
635
-
636
-
637
-		//try to configure php to enable big file uploads.
638
-		//this doesn´t work always depending on the webserver and php configuration.
639
-		//Let´s try to overwrite some defaults if they are smaller than 1 hour
640
-
641
-		if (intval(@ini_get('max_execution_time') ?? 0) < 3600) {
642
-			@ini_set('max_execution_time', strval(3600));
643
-		}
644
-
645
-		if (intval(@ini_get('max_input_time') ?? 0) < 3600) {
646
-			@ini_set('max_input_time', strval(3600));
647
-		}
648
-
649
-		//try to set the maximum execution time to the largest time limit we have
650
-		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
651
-			@set_time_limit(max(intval(@ini_get('max_execution_time')), intval(@ini_get('max_input_time'))));
652
-		}
653
-
654
-		self::setRequiredIniValues();
655
-		self::handleAuthHeaders();
656
-		$systemConfig = \OC::$server->get(\OC\SystemConfig::class);
657
-		self::registerAutoloaderCache($systemConfig);
658
-
659
-		// initialize intl fallback if necessary
660
-		OC_Util::isSetLocaleWorking();
661
-
662
-		$config = \OC::$server->get(\OCP\IConfig::class);
663
-		if (!defined('PHPUNIT_RUN')) {
664
-			OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
665
-			$debug = $config->getSystemValue('debug', false);
666
-			OC\Log\ErrorHandler::register($debug);
667
-		}
668
-
669
-		/** @var \OC\AppFramework\Bootstrap\Coordinator $bootstrapCoordinator */
670
-		$bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
671
-		$bootstrapCoordinator->runInitialRegistration();
672
-
673
-		$eventLogger->start('init_session', 'Initialize session');
674
-		OC_App::loadApps(['session']);
675
-		if (!self::$CLI) {
676
-			self::initSession();
677
-		}
678
-		$eventLogger->end('init_session');
679
-		self::checkConfig();
680
-		self::checkInstalled($systemConfig);
681
-
682
-		OC_Response::addSecurityHeaders();
683
-
684
-		self::performSameSiteCookieProtection($config);
685
-
686
-		if (!defined('OC_CONSOLE')) {
687
-			$errors = OC_Util::checkServer($systemConfig);
688
-			if (count($errors) > 0) {
689
-				if (!self::$CLI) {
690
-					http_response_code(503);
691
-					OC_Util::addStyle('guest');
692
-					try {
693
-						OC_Template::printGuestPage('', 'error', ['errors' => $errors]);
694
-						exit;
695
-					} catch (\Exception $e) {
696
-						// In case any error happens when showing the error page, we simply fall back to posting the text.
697
-						// This might be the case when e.g. the data directory is broken and we can not load/write SCSS to/from it.
698
-					}
699
-				}
700
-
701
-				// Convert l10n string into regular string for usage in database
702
-				$staticErrors = [];
703
-				foreach ($errors as $error) {
704
-					echo $error['error'] . "\n";
705
-					echo $error['hint'] . "\n\n";
706
-					$staticErrors[] = [
707
-						'error' => (string)$error['error'],
708
-						'hint' => (string)$error['hint'],
709
-					];
710
-				}
711
-
712
-				try {
713
-					$config->setAppValue('core', 'cronErrors', json_encode($staticErrors));
714
-				} catch (\Exception $e) {
715
-					echo('Writing to database failed');
716
-				}
717
-				exit(1);
718
-			} elseif (self::$CLI && $config->getSystemValue('installed', false)) {
719
-				$config->deleteAppValue('core', 'cronErrors');
720
-			}
721
-		}
722
-
723
-		// User and Groups
724
-		if (!$systemConfig->getValue("installed", false)) {
725
-			self::$server->getSession()->set('user_id', '');
726
-		}
727
-
728
-		OC_User::useBackend(new \OC\User\Database());
729
-		\OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
730
-
731
-		// Subscribe to the hook
732
-		\OCP\Util::connectHook(
733
-			'\OCA\Files_Sharing\API\Server2Server',
734
-			'preLoginNameUsedAsUserName',
735
-			'\OC\User\Database',
736
-			'preLoginNameUsedAsUserName'
737
-		);
738
-
739
-		//setup extra user backends
740
-		if (!\OCP\Util::needUpgrade()) {
741
-			OC_User::setupBackends();
742
-		} else {
743
-			// Run upgrades in incognito mode
744
-			OC_User::setIncognitoMode(true);
745
-		}
746
-
747
-		self::registerCleanupHooks($systemConfig);
748
-		self::registerShareHooks($systemConfig);
749
-		self::registerEncryptionWrapperAndHooks();
750
-		self::registerAccountHooks();
751
-		self::registerResourceCollectionHooks();
752
-		self::registerFileReferenceEventListener();
753
-		self::registerAppRestrictionsHooks();
754
-
755
-		// Make sure that the application class is not loaded before the database is setup
756
-		if ($systemConfig->getValue("installed", false)) {
757
-			OC_App::loadApp('settings');
758
-			/* Build core application to make sure that listeners are registered */
759
-			self::$server->get(\OC\Core\Application::class);
760
-		}
761
-
762
-		//make sure temporary files are cleaned up
763
-		$tmpManager = \OC::$server->getTempManager();
764
-		register_shutdown_function([$tmpManager, 'clean']);
765
-		$lockProvider = \OC::$server->getLockingProvider();
766
-		register_shutdown_function([$lockProvider, 'releaseAll']);
767
-
768
-		// Check whether the sample configuration has been copied
769
-		if ($systemConfig->getValue('copied_sample_config', false)) {
770
-			$l = \OC::$server->getL10N('lib');
771
-			OC_Template::printErrorPage(
772
-				$l->t('Sample configuration detected'),
773
-				$l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php'),
774
-				503
775
-			);
776
-			return;
777
-		}
778
-
779
-		$request = \OC::$server->getRequest();
780
-		$host = $request->getInsecureServerHost();
781
-		/**
782
-		 * if the host passed in headers isn't trusted
783
-		 * FIXME: Should not be in here at all :see_no_evil:
784
-		 */
785
-		if (!OC::$CLI
786
-			&& !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
787
-			&& $config->getSystemValue('installed', false)
788
-		) {
789
-			// Allow access to CSS resources
790
-			$isScssRequest = false;
791
-			if (strpos($request->getPathInfo(), '/css/') === 0) {
792
-				$isScssRequest = true;
793
-			}
794
-
795
-			if (substr($request->getRequestUri(), -11) === '/status.php') {
796
-				http_response_code(400);
797
-				header('Content-Type: application/json');
798
-				echo '{"error": "Trusted domain error.", "code": 15}';
799
-				exit();
800
-			}
801
-
802
-			if (!$isScssRequest) {
803
-				http_response_code(400);
804
-
805
-				\OC::$server->getLogger()->warning(
806
-					'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
807
-					[
808
-						'app' => 'core',
809
-						'remoteAddress' => $request->getRemoteAddress(),
810
-						'host' => $host,
811
-					]
812
-				);
813
-
814
-				$tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
815
-				$tmpl->assign('docUrl', \OC::$server->getURLGenerator()->linkToDocs('admin-trusted-domains'));
816
-				$tmpl->printPage();
817
-
818
-				exit();
819
-			}
820
-		}
821
-		$eventLogger->end('boot');
822
-		$eventLogger->log('init', 'OC::init', $loaderStart, microtime(true));
823
-		$eventLogger->start('runtime', 'Runtime');
824
-		$eventLogger->start('request', 'Full request after boot');
825
-		register_shutdown_function(function () use ($eventLogger) {
826
-			$eventLogger->end('request');
827
-		});
828
-	}
829
-
830
-	/**
831
-	 * register hooks for the cleanup of cache and bruteforce protection
832
-	 */
833
-	public static function registerCleanupHooks(\OC\SystemConfig $systemConfig) {
834
-		//don't try to do this before we are properly setup
835
-		if ($systemConfig->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
836
-
837
-			// NOTE: This will be replaced to use OCP
838
-			$userSession = self::$server->getUserSession();
839
-			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
840
-				if (!defined('PHPUNIT_RUN') && $userSession->isLoggedIn()) {
841
-					// reset brute force delay for this IP address and username
842
-					$uid = \OC::$server->getUserSession()->getUser()->getUID();
843
-					$request = \OC::$server->getRequest();
844
-					$throttler = \OC::$server->getBruteForceThrottler();
845
-					$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
846
-				}
847
-
848
-				try {
849
-					$cache = new \OC\Cache\File();
850
-					$cache->gc();
851
-				} catch (\OC\ServerNotAvailableException $e) {
852
-					// not a GC exception, pass it on
853
-					throw $e;
854
-				} catch (\OC\ForbiddenException $e) {
855
-					// filesystem blocked for this request, ignore
856
-				} catch (\Exception $e) {
857
-					// a GC exception should not prevent users from using OC,
858
-					// so log the exception
859
-					\OC::$server->getLogger()->logException($e, [
860
-						'message' => 'Exception when running cache gc.',
861
-						'level' => ILogger::WARN,
862
-						'app' => 'core',
863
-					]);
864
-				}
865
-			});
866
-		}
867
-	}
868
-
869
-	private static function registerEncryptionWrapperAndHooks() {
870
-		$manager = self::$server->getEncryptionManager();
871
-		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
872
-
873
-		$enabled = $manager->isEnabled();
874
-		if ($enabled) {
875
-			\OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
876
-			\OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
877
-			\OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
878
-			\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
879
-		}
880
-	}
881
-
882
-	private static function registerAccountHooks() {
883
-		/** @var IEventDispatcher $dispatcher */
884
-		$dispatcher = \OC::$server->get(IEventDispatcher::class);
885
-		$dispatcher->addServiceListener(UserChangedEvent::class, \OC\Accounts\Hooks::class);
886
-	}
887
-
888
-	private static function registerAppRestrictionsHooks() {
889
-		/** @var \OC\Group\Manager $groupManager */
890
-		$groupManager = self::$server->query(\OCP\IGroupManager::class);
891
-		$groupManager->listen('\OC\Group', 'postDelete', function (\OCP\IGroup $group) {
892
-			$appManager = self::$server->getAppManager();
893
-			$apps = $appManager->getEnabledAppsForGroup($group);
894
-			foreach ($apps as $appId) {
895
-				$restrictions = $appManager->getAppRestriction($appId);
896
-				if (empty($restrictions)) {
897
-					continue;
898
-				}
899
-				$key = array_search($group->getGID(), $restrictions);
900
-				unset($restrictions[$key]);
901
-				$restrictions = array_values($restrictions);
902
-				if (empty($restrictions)) {
903
-					$appManager->disableApp($appId);
904
-				} else {
905
-					$appManager->enableAppForGroups($appId, $restrictions);
906
-				}
907
-			}
908
-		});
909
-	}
910
-
911
-	private static function registerResourceCollectionHooks() {
912
-		\OC\Collaboration\Resources\Listener::register(Server::get(SymfonyAdapter::class), Server::get(IEventDispatcher::class));
913
-	}
914
-
915
-	private static function registerFileReferenceEventListener() {
916
-		\OC\Collaboration\Reference\File\FileReferenceEventListener::register(Server::get(IEventDispatcher::class));
917
-	}
918
-
919
-	/**
920
-	 * register hooks for sharing
921
-	 */
922
-	public static function registerShareHooks(\OC\SystemConfig $systemConfig) {
923
-		if ($systemConfig->getValue('installed')) {
924
-			OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
925
-			OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
926
-
927
-			/** @var IEventDispatcher $dispatcher */
928
-			$dispatcher = \OC::$server->get(IEventDispatcher::class);
929
-			$dispatcher->addServiceListener(UserRemovedEvent::class, \OC\Share20\UserRemovedListener::class);
930
-		}
931
-	}
932
-
933
-	protected static function registerAutoloaderCache(\OC\SystemConfig $systemConfig) {
934
-		// The class loader takes an optional low-latency cache, which MUST be
935
-		// namespaced. The instanceid is used for namespacing, but might be
936
-		// unavailable at this point. Furthermore, it might not be possible to
937
-		// generate an instanceid via \OC_Util::getInstanceId() because the
938
-		// config file may not be writable. As such, we only register a class
939
-		// loader cache if instanceid is available without trying to create one.
940
-		$instanceId = $systemConfig->getValue('instanceid', null);
941
-		if ($instanceId) {
942
-			try {
943
-				$memcacheFactory = \OC::$server->getMemCacheFactory();
944
-				self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
945
-			} catch (\Exception $ex) {
946
-			}
947
-		}
948
-	}
949
-
950
-	/**
951
-	 * Handle the request
952
-	 */
953
-	public static function handleRequest() {
954
-		\OC::$server->getEventLogger()->start('handle_request', 'Handle request');
955
-		$systemConfig = \OC::$server->getSystemConfig();
956
-
957
-		// Check if Nextcloud is installed or in maintenance (update) mode
958
-		if (!$systemConfig->getValue('installed', false)) {
959
-			\OC::$server->getSession()->clear();
960
-			$setupHelper = new OC\Setup(
961
-				$systemConfig,
962
-				\OC::$server->get(\bantu\IniGetWrapper\IniGetWrapper::class),
963
-				\OC::$server->getL10N('lib'),
964
-				\OC::$server->query(\OCP\Defaults::class),
965
-				\OC::$server->get(\Psr\Log\LoggerInterface::class),
966
-				\OC::$server->getSecureRandom(),
967
-				\OC::$server->query(\OC\Installer::class)
968
-			);
969
-			$controller = new OC\Core\Controller\SetupController($setupHelper);
970
-			$controller->run($_POST);
971
-			exit();
972
-		}
973
-
974
-		$request = \OC::$server->getRequest();
975
-		$requestPath = $request->getRawPathInfo();
976
-		if ($requestPath === '/heartbeat') {
977
-			return;
978
-		}
979
-		if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
980
-			self::checkMaintenanceMode($systemConfig);
981
-
982
-			if (\OCP\Util::needUpgrade()) {
983
-				if (function_exists('opcache_reset')) {
984
-					opcache_reset();
985
-				}
986
-				if (!((bool) $systemConfig->getValue('maintenance', false))) {
987
-					self::printUpgradePage($systemConfig);
988
-					exit();
989
-				}
990
-			}
991
-		}
992
-
993
-		// emergency app disabling
994
-		if ($requestPath === '/disableapp'
995
-			&& $request->getMethod() === 'POST'
996
-			&& ((array)$request->getParam('appid')) !== ''
997
-		) {
998
-			\OC_JSON::callCheck();
999
-			\OC_JSON::checkAdminUser();
1000
-			$appIds = (array)$request->getParam('appid');
1001
-			foreach ($appIds as $appId) {
1002
-				$appId = \OC_App::cleanAppId($appId);
1003
-				\OC::$server->getAppManager()->disableApp($appId);
1004
-			}
1005
-			\OC_JSON::success();
1006
-			exit();
1007
-		}
1008
-
1009
-		// Always load authentication apps
1010
-		OC_App::loadApps(['authentication']);
1011
-
1012
-		// Load minimum set of apps
1013
-		if (!\OCP\Util::needUpgrade()
1014
-			&& !((bool) $systemConfig->getValue('maintenance', false))) {
1015
-			// For logged-in users: Load everything
1016
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1017
-				OC_App::loadApps();
1018
-			} else {
1019
-				// For guests: Load only filesystem and logging
1020
-				OC_App::loadApps(['filesystem', 'logging']);
1021
-
1022
-				// Don't try to login when a client is trying to get a OAuth token.
1023
-				// OAuth needs to support basic auth too, so the login is not valid
1024
-				// inside Nextcloud and the Login exception would ruin it.
1025
-				if ($request->getRawPathInfo() !== '/apps/oauth2/api/v1/token') {
1026
-					self::handleLogin($request);
1027
-				}
1028
-			}
1029
-		}
1030
-
1031
-		if (!self::$CLI) {
1032
-			try {
1033
-				if (!((bool) $systemConfig->getValue('maintenance', false)) && !\OCP\Util::needUpgrade()) {
1034
-					OC_App::loadApps(['filesystem', 'logging']);
1035
-					OC_App::loadApps();
1036
-				}
1037
-				OC::$server->get(\OC\Route\Router::class)->match($request->getRawPathInfo());
1038
-				return;
1039
-			} catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
1040
-				//header('HTTP/1.0 404 Not Found');
1041
-			} catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
1042
-				http_response_code(405);
1043
-				return;
1044
-			}
1045
-		}
1046
-
1047
-		// Handle WebDAV
1048
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
1049
-			// not allowed any more to prevent people
1050
-			// mounting this root directly.
1051
-			// Users need to mount remote.php/webdav instead.
1052
-			http_response_code(405);
1053
-			return;
1054
-		}
1055
-
1056
-		// Handle requests for JSON or XML
1057
-		$acceptHeader = $request->getHeader('Accept');
1058
-		if (in_array($acceptHeader, ['application/json', 'application/xml'], true)) {
1059
-			http_response_code(404);
1060
-			return;
1061
-		}
1062
-
1063
-		// Handle resources that can't be found
1064
-		// This prevents browsers from redirecting to the default page and then
1065
-		// attempting to parse HTML as CSS and similar.
1066
-		$destinationHeader = $request->getHeader('Sec-Fetch-Dest');
1067
-		if (in_array($destinationHeader, ['font', 'script', 'style'])) {
1068
-			http_response_code(404);
1069
-			return;
1070
-		}
1071
-
1072
-		// Someone is logged in
1073
-		if (\OC::$server->getUserSession()->isLoggedIn()) {
1074
-			OC_App::loadApps();
1075
-			OC_User::setupBackends();
1076
-			OC_Util::setupFS();
1077
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToDefaultPageUrl());
1078
-		} else {
1079
-			// Not handled and not logged in
1080
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1081
-		}
1082
-	}
1083
-
1084
-	/**
1085
-	 * Check login: apache auth, auth token, basic auth
1086
-	 *
1087
-	 * @param OCP\IRequest $request
1088
-	 * @return boolean
1089
-	 */
1090
-	public static function handleLogin(OCP\IRequest $request) {
1091
-		$userSession = self::$server->getUserSession();
1092
-		if (OC_User::handleApacheAuth()) {
1093
-			return true;
1094
-		}
1095
-		if ($userSession->tryTokenLogin($request)) {
1096
-			return true;
1097
-		}
1098
-		if (isset($_COOKIE['nc_username'])
1099
-			&& isset($_COOKIE['nc_token'])
1100
-			&& isset($_COOKIE['nc_session_id'])
1101
-			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1102
-			return true;
1103
-		}
1104
-		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1105
-			return true;
1106
-		}
1107
-		return false;
1108
-	}
1109
-
1110
-	protected static function handleAuthHeaders() {
1111
-		//copy http auth headers for apache+php-fcgid work around
1112
-		if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1113
-			$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1114
-		}
1115
-
1116
-		// Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1117
-		$vars = [
1118
-			'HTTP_AUTHORIZATION', // apache+php-cgi work around
1119
-			'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1120
-		];
1121
-		foreach ($vars as $var) {
1122
-			if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1123
-				$credentials = explode(':', base64_decode($matches[1]), 2);
1124
-				if (count($credentials) === 2) {
1125
-					$_SERVER['PHP_AUTH_USER'] = $credentials[0];
1126
-					$_SERVER['PHP_AUTH_PW'] = $credentials[1];
1127
-					break;
1128
-				}
1129
-			}
1130
-		}
1131
-	}
84
+    /**
85
+     * Associative array for autoloading. classname => filename
86
+     */
87
+    public static $CLASSPATH = [];
88
+    /**
89
+     * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
90
+     */
91
+    public static $SERVERROOT = '';
92
+    /**
93
+     * the current request path relative to the Nextcloud root (e.g. files/index.php)
94
+     */
95
+    private static $SUBURI = '';
96
+    /**
97
+     * the Nextcloud root path for http requests (e.g. nextcloud/)
98
+     */
99
+    public static $WEBROOT = '';
100
+    /**
101
+     * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
102
+     * web path in 'url'
103
+     */
104
+    public static $APPSROOTS = [];
105
+
106
+    /**
107
+     * @var string
108
+     */
109
+    public static $configDir;
110
+
111
+    /**
112
+     * requested app
113
+     */
114
+    public static $REQUESTEDAPP = '';
115
+
116
+    /**
117
+     * check if Nextcloud runs in cli mode
118
+     */
119
+    public static $CLI = false;
120
+
121
+    /**
122
+     * @var \OC\Autoloader $loader
123
+     */
124
+    public static $loader = null;
125
+
126
+    /** @var \Composer\Autoload\ClassLoader $composerAutoloader */
127
+    public static $composerAutoloader = null;
128
+
129
+    /**
130
+     * @var \OC\Server
131
+     */
132
+    public static $server = null;
133
+
134
+    /**
135
+     * @var \OC\Config
136
+     */
137
+    private static $config = null;
138
+
139
+    /**
140
+     * @throws \RuntimeException when the 3rdparty directory is missing or
141
+     * the app path list is empty or contains an invalid path
142
+     */
143
+    public static function initPaths() {
144
+        if (defined('PHPUNIT_CONFIG_DIR')) {
145
+            self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
146
+        } elseif (defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
147
+            self::$configDir = OC::$SERVERROOT . '/tests/config/';
148
+        } elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
149
+            self::$configDir = rtrim($dir, '/') . '/';
150
+        } else {
151
+            self::$configDir = OC::$SERVERROOT . '/config/';
152
+        }
153
+        self::$config = new \OC\Config(self::$configDir);
154
+
155
+        OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
156
+        /**
157
+         * FIXME: The following lines are required because we can't yet instantiate
158
+         *        \OC::$server->getRequest() since \OC::$server does not yet exist.
159
+         */
160
+        $params = [
161
+            'server' => [
162
+                'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
163
+                'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
164
+            ],
165
+        ];
166
+        $fakeRequest = new \OC\AppFramework\Http\Request(
167
+            $params,
168
+            new \OC\AppFramework\Http\RequestId($_SERVER['UNIQUE_ID'] ?? '', new \OC\Security\SecureRandom()),
169
+            new \OC\AllConfig(new \OC\SystemConfig(self::$config))
170
+        );
171
+        $scriptName = $fakeRequest->getScriptName();
172
+        if (substr($scriptName, -1) == '/') {
173
+            $scriptName .= 'index.php';
174
+            //make sure suburi follows the same rules as scriptName
175
+            if (substr(OC::$SUBURI, -9) != 'index.php') {
176
+                if (substr(OC::$SUBURI, -1) != '/') {
177
+                    OC::$SUBURI = OC::$SUBURI . '/';
178
+                }
179
+                OC::$SUBURI = OC::$SUBURI . 'index.php';
180
+            }
181
+        }
182
+
183
+
184
+        if (OC::$CLI) {
185
+            OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
186
+        } else {
187
+            if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
188
+                OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
189
+
190
+                if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
191
+                    OC::$WEBROOT = '/' . OC::$WEBROOT;
192
+                }
193
+            } else {
194
+                // The scriptName is not ending with OC::$SUBURI
195
+                // This most likely means that we are calling from CLI.
196
+                // However some cron jobs still need to generate
197
+                // a web URL, so we use overwritewebroot as a fallback.
198
+                OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
199
+            }
200
+
201
+            // Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
202
+            // slash which is required by URL generation.
203
+            if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
204
+                    substr($_SERVER['REQUEST_URI'], -1) !== '/') {
205
+                header('Location: '.\OC::$WEBROOT.'/');
206
+                exit();
207
+            }
208
+        }
209
+
210
+        // search the apps folder
211
+        $config_paths = self::$config->getValue('apps_paths', []);
212
+        if (!empty($config_paths)) {
213
+            foreach ($config_paths as $paths) {
214
+                if (isset($paths['url']) && isset($paths['path'])) {
215
+                    $paths['url'] = rtrim($paths['url'], '/');
216
+                    $paths['path'] = rtrim($paths['path'], '/');
217
+                    OC::$APPSROOTS[] = $paths;
218
+                }
219
+            }
220
+        } elseif (file_exists(OC::$SERVERROOT . '/apps')) {
221
+            OC::$APPSROOTS[] = ['path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true];
222
+        }
223
+
224
+        if (empty(OC::$APPSROOTS)) {
225
+            throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
226
+                . '. You can also configure the location in the config.php file.');
227
+        }
228
+        $paths = [];
229
+        foreach (OC::$APPSROOTS as $path) {
230
+            $paths[] = $path['path'];
231
+            if (!is_dir($path['path'])) {
232
+                throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
233
+                    . ' Nextcloud folder. You can also configure the location in the config.php file.', $path['path']));
234
+            }
235
+        }
236
+
237
+        // set the right include path
238
+        set_include_path(
239
+            implode(PATH_SEPARATOR, $paths)
240
+        );
241
+    }
242
+
243
+    public static function checkConfig() {
244
+        $l = \OC::$server->getL10N('lib');
245
+
246
+        // Create config if it does not already exist
247
+        $configFilePath = self::$configDir .'/config.php';
248
+        if (!file_exists($configFilePath)) {
249
+            @touch($configFilePath);
250
+        }
251
+
252
+        // Check if config is writable
253
+        $configFileWritable = is_writable($configFilePath);
254
+        if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
255
+            || !$configFileWritable && \OCP\Util::needUpgrade()) {
256
+            $urlGenerator = \OC::$server->getURLGenerator();
257
+
258
+            if (self::$CLI) {
259
+                echo $l->t('Cannot write into "config" directory!')."\n";
260
+                echo $l->t('This can usually be fixed by giving the web server write access to the config directory.')."\n";
261
+                echo "\n";
262
+                echo $l->t('But, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it.')."\n";
263
+                echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-config') ])."\n";
264
+                exit;
265
+            } else {
266
+                OC_Template::printErrorPage(
267
+                    $l->t('Cannot write into "config" directory!'),
268
+                    $l->t('This can usually be fixed by giving the web server write access to the config directory.') . ' '
269
+                    . $l->t('But, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it.') . ' '
270
+                    . $l->t('See %s', [ $urlGenerator->linkToDocs('admin-config') ]),
271
+                    503
272
+                );
273
+            }
274
+        }
275
+    }
276
+
277
+    public static function checkInstalled(\OC\SystemConfig $systemConfig) {
278
+        if (defined('OC_CONSOLE')) {
279
+            return;
280
+        }
281
+        // Redirect to installer if not installed
282
+        if (!$systemConfig->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
283
+            if (OC::$CLI) {
284
+                throw new Exception('Not installed');
285
+            } else {
286
+                $url = OC::$WEBROOT . '/index.php';
287
+                header('Location: ' . $url);
288
+            }
289
+            exit();
290
+        }
291
+    }
292
+
293
+    public static function checkMaintenanceMode(\OC\SystemConfig $systemConfig) {
294
+        // Allow ajax update script to execute without being stopped
295
+        if (((bool) $systemConfig->getValue('maintenance', false)) && OC::$SUBURI != '/core/ajax/update.php') {
296
+            // send http status 503
297
+            http_response_code(503);
298
+            header('X-Nextcloud-Maintenance-Mode: 1');
299
+            header('Retry-After: 120');
300
+
301
+            // render error page
302
+            $template = new OC_Template('', 'update.user', 'guest');
303
+            \OCP\Util::addScript('core', 'maintenance');
304
+            \OCP\Util::addStyle('core', 'guest');
305
+            $template->printPage();
306
+            die();
307
+        }
308
+    }
309
+
310
+    /**
311
+     * Prints the upgrade page
312
+     *
313
+     * @param \OC\SystemConfig $systemConfig
314
+     */
315
+    private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
316
+        $disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
317
+        $tooBig = false;
318
+        if (!$disableWebUpdater) {
319
+            $apps = \OC::$server->getAppManager();
320
+            if ($apps->isInstalled('user_ldap')) {
321
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
322
+
323
+                $result = $qb->select($qb->func()->count('*', 'user_count'))
324
+                    ->from('ldap_user_mapping')
325
+                    ->execute();
326
+                $row = $result->fetch();
327
+                $result->closeCursor();
328
+
329
+                $tooBig = ($row['user_count'] > 50);
330
+            }
331
+            if (!$tooBig && $apps->isInstalled('user_saml')) {
332
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
333
+
334
+                $result = $qb->select($qb->func()->count('*', 'user_count'))
335
+                    ->from('user_saml_users')
336
+                    ->execute();
337
+                $row = $result->fetch();
338
+                $result->closeCursor();
339
+
340
+                $tooBig = ($row['user_count'] > 50);
341
+            }
342
+            if (!$tooBig) {
343
+                // count users
344
+                $stats = \OC::$server->getUserManager()->countUsers();
345
+                $totalUsers = array_sum($stats);
346
+                $tooBig = ($totalUsers > 50);
347
+            }
348
+        }
349
+        $ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
350
+            $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
351
+
352
+        if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
353
+            // send http status 503
354
+            http_response_code(503);
355
+            header('Retry-After: 120');
356
+
357
+            // render error page
358
+            $template = new OC_Template('', 'update.use-cli', 'guest');
359
+            $template->assign('productName', 'nextcloud'); // for now
360
+            $template->assign('version', OC_Util::getVersionString());
361
+            $template->assign('tooBig', $tooBig);
362
+
363
+            $template->printPage();
364
+            die();
365
+        }
366
+
367
+        // check whether this is a core update or apps update
368
+        $installedVersion = $systemConfig->getValue('version', '0.0.0');
369
+        $currentVersion = implode('.', \OCP\Util::getVersion());
370
+
371
+        // if not a core upgrade, then it's apps upgrade
372
+        $isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
373
+
374
+        $oldTheme = $systemConfig->getValue('theme');
375
+        $systemConfig->setValue('theme', '');
376
+        \OCP\Util::addScript('core', 'common');
377
+        \OCP\Util::addScript('core', 'main');
378
+        \OCP\Util::addTranslations('core');
379
+        \OCP\Util::addScript('core', 'update');
380
+
381
+        /** @var \OC\App\AppManager $appManager */
382
+        $appManager = \OC::$server->getAppManager();
383
+
384
+        $tmpl = new OC_Template('', 'update.admin', 'guest');
385
+        $tmpl->assign('version', OC_Util::getVersionString());
386
+        $tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
387
+
388
+        // get third party apps
389
+        $ocVersion = \OCP\Util::getVersion();
390
+        $ocVersion = implode('.', $ocVersion);
391
+        $incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
392
+        $incompatibleShippedApps = [];
393
+        foreach ($incompatibleApps as $appInfo) {
394
+            if ($appManager->isShipped($appInfo['id'])) {
395
+                $incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
396
+            }
397
+        }
398
+
399
+        if (!empty($incompatibleShippedApps)) {
400
+            $l = \OC::$server->getL10N('core');
401
+            $hint = $l->t('The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
402
+            throw new \OCP\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
403
+        }
404
+
405
+        $tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
406
+        $tmpl->assign('incompatibleAppsList', $incompatibleApps);
407
+        try {
408
+            $defaults = new \OC_Defaults();
409
+            $tmpl->assign('productName', $defaults->getName());
410
+        } catch (Throwable $error) {
411
+            $tmpl->assign('productName', 'Nextcloud');
412
+        }
413
+        $tmpl->assign('oldTheme', $oldTheme);
414
+        $tmpl->printPage();
415
+    }
416
+
417
+    public static function initSession() {
418
+        if (self::$server->getRequest()->getServerProtocol() === 'https') {
419
+            ini_set('session.cookie_secure', 'true');
420
+        }
421
+
422
+        // prevents javascript from accessing php session cookies
423
+        ini_set('session.cookie_httponly', 'true');
424
+
425
+        // set the cookie path to the Nextcloud directory
426
+        $cookie_path = OC::$WEBROOT ? : '/';
427
+        ini_set('session.cookie_path', $cookie_path);
428
+
429
+        // Let the session name be changed in the initSession Hook
430
+        $sessionName = OC_Util::getInstanceId();
431
+
432
+        try {
433
+            // set the session name to the instance id - which is unique
434
+            $session = new \OC\Session\Internal($sessionName);
435
+
436
+            $cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
437
+            $session = $cryptoWrapper->wrapSession($session);
438
+            self::$server->setSession($session);
439
+
440
+            // if session can't be started break with http 500 error
441
+        } catch (Exception $e) {
442
+            \OC::$server->getLogger()->logException($e, ['app' => 'base']);
443
+            //show the user a detailed error page
444
+            OC_Template::printExceptionErrorPage($e, 500);
445
+            die();
446
+        }
447
+
448
+        //try to set the session lifetime
449
+        $sessionLifeTime = self::getSessionLifeTime();
450
+        @ini_set('gc_maxlifetime', (string)$sessionLifeTime);
451
+
452
+        // session timeout
453
+        if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
454
+            if (isset($_COOKIE[session_name()])) {
455
+                setcookie(session_name(), '', -1, self::$WEBROOT ? : '/');
456
+            }
457
+            \OC::$server->getUserSession()->logout();
458
+        }
459
+
460
+        if (!self::hasSessionRelaxedExpiry()) {
461
+            $session->set('LAST_ACTIVITY', time());
462
+        }
463
+        $session->close();
464
+    }
465
+
466
+    /**
467
+     * @return string
468
+     */
469
+    private static function getSessionLifeTime() {
470
+        return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
471
+    }
472
+
473
+    /**
474
+     * @return bool true if the session expiry should only be done by gc instead of an explicit timeout
475
+     */
476
+    public static function hasSessionRelaxedExpiry(): bool {
477
+        return \OC::$server->getConfig()->getSystemValue('session_relaxed_expiry', false);
478
+    }
479
+
480
+    /**
481
+     * Try to set some values to the required Nextcloud default
482
+     */
483
+    public static function setRequiredIniValues() {
484
+        @ini_set('default_charset', 'UTF-8');
485
+        @ini_set('gd.jpeg_ignore_warning', '1');
486
+    }
487
+
488
+    /**
489
+     * Send the same site cookies
490
+     */
491
+    private static function sendSameSiteCookies() {
492
+        $cookieParams = session_get_cookie_params();
493
+        $secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
494
+        $policies = [
495
+            'lax',
496
+            'strict',
497
+        ];
498
+
499
+        // Append __Host to the cookie if it meets the requirements
500
+        $cookiePrefix = '';
501
+        if ($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
502
+            $cookiePrefix = '__Host-';
503
+        }
504
+
505
+        foreach ($policies as $policy) {
506
+            header(
507
+                sprintf(
508
+                    'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
509
+                    $cookiePrefix,
510
+                    $policy,
511
+                    $cookieParams['path'],
512
+                    $policy
513
+                ),
514
+                false
515
+            );
516
+        }
517
+    }
518
+
519
+    /**
520
+     * Same Site cookie to further mitigate CSRF attacks. This cookie has to
521
+     * be set in every request if cookies are sent to add a second level of
522
+     * defense against CSRF.
523
+     *
524
+     * If the cookie is not sent this will set the cookie and reload the page.
525
+     * We use an additional cookie since we want to protect logout CSRF and
526
+     * also we can't directly interfere with PHP's session mechanism.
527
+     */
528
+    private static function performSameSiteCookieProtection(\OCP\IConfig $config) {
529
+        $request = \OC::$server->getRequest();
530
+
531
+        // Some user agents are notorious and don't really properly follow HTTP
532
+        // specifications. For those, have an automated opt-out. Since the protection
533
+        // for remote.php is applied in base.php as starting point we need to opt out
534
+        // here.
535
+        $incompatibleUserAgents = $config->getSystemValue('csrf.optout');
536
+
537
+        // Fallback, if csrf.optout is unset
538
+        if (!is_array($incompatibleUserAgents)) {
539
+            $incompatibleUserAgents = [
540
+                // OS X Finder
541
+                '/^WebDAVFS/',
542
+                // Windows webdav drive
543
+                '/^Microsoft-WebDAV-MiniRedir/',
544
+            ];
545
+        }
546
+
547
+        if ($request->isUserAgent($incompatibleUserAgents)) {
548
+            return;
549
+        }
550
+
551
+        if (count($_COOKIE) > 0) {
552
+            $requestUri = $request->getScriptName();
553
+            $processingScript = explode('/', $requestUri);
554
+            $processingScript = $processingScript[count($processingScript) - 1];
555
+
556
+            // index.php routes are handled in the middleware
557
+            if ($processingScript === 'index.php') {
558
+                return;
559
+            }
560
+
561
+            // All other endpoints require the lax and the strict cookie
562
+            if (!$request->passesStrictCookieCheck()) {
563
+                self::sendSameSiteCookies();
564
+                // Debug mode gets access to the resources without strict cookie
565
+                // due to the fact that the SabreDAV browser also lives there.
566
+                if (!$config->getSystemValue('debug', false)) {
567
+                    http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
568
+                    exit();
569
+                }
570
+            }
571
+        } elseif (!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
572
+            self::sendSameSiteCookies();
573
+        }
574
+    }
575
+
576
+    public static function init() {
577
+        // calculate the root directories
578
+        OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
579
+
580
+        // register autoloader
581
+        $loaderStart = microtime(true);
582
+        require_once __DIR__ . '/autoloader.php';
583
+        self::$loader = new \OC\Autoloader([
584
+            OC::$SERVERROOT . '/lib/private/legacy',
585
+        ]);
586
+        if (defined('PHPUNIT_RUN')) {
587
+            self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
588
+        }
589
+        spl_autoload_register([self::$loader, 'load']);
590
+        $loaderEnd = microtime(true);
591
+
592
+        self::$CLI = (php_sapi_name() == 'cli');
593
+
594
+        // Add default composer PSR-4 autoloader
595
+        self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
596
+
597
+        try {
598
+            self::initPaths();
599
+            // setup 3rdparty autoloader
600
+            $vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
601
+            if (!file_exists($vendorAutoLoad)) {
602
+                throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
603
+            }
604
+            require_once $vendorAutoLoad;
605
+        } catch (\RuntimeException $e) {
606
+            if (!self::$CLI) {
607
+                http_response_code(503);
608
+            }
609
+            // we can't use the template error page here, because this needs the
610
+            // DI container which isn't available yet
611
+            print($e->getMessage());
612
+            exit();
613
+        }
614
+
615
+        // setup the basic server
616
+        self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
617
+        self::$server->boot();
618
+
619
+        $eventLogger = \OC::$server->getEventLogger();
620
+        $eventLogger->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
621
+        $eventLogger->start('boot', 'Initialize');
622
+
623
+        // Override php.ini and log everything if we're troubleshooting
624
+        if (self::$config->getValue('loglevel') === ILogger::DEBUG) {
625
+            error_reporting(E_ALL);
626
+        }
627
+
628
+        // Don't display errors and log them
629
+        @ini_set('display_errors', '0');
630
+        @ini_set('log_errors', '1');
631
+
632
+        if (!date_default_timezone_set('UTC')) {
633
+            throw new \RuntimeException('Could not set timezone to UTC');
634
+        }
635
+
636
+
637
+        //try to configure php to enable big file uploads.
638
+        //this doesn´t work always depending on the webserver and php configuration.
639
+        //Let´s try to overwrite some defaults if they are smaller than 1 hour
640
+
641
+        if (intval(@ini_get('max_execution_time') ?? 0) < 3600) {
642
+            @ini_set('max_execution_time', strval(3600));
643
+        }
644
+
645
+        if (intval(@ini_get('max_input_time') ?? 0) < 3600) {
646
+            @ini_set('max_input_time', strval(3600));
647
+        }
648
+
649
+        //try to set the maximum execution time to the largest time limit we have
650
+        if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
651
+            @set_time_limit(max(intval(@ini_get('max_execution_time')), intval(@ini_get('max_input_time'))));
652
+        }
653
+
654
+        self::setRequiredIniValues();
655
+        self::handleAuthHeaders();
656
+        $systemConfig = \OC::$server->get(\OC\SystemConfig::class);
657
+        self::registerAutoloaderCache($systemConfig);
658
+
659
+        // initialize intl fallback if necessary
660
+        OC_Util::isSetLocaleWorking();
661
+
662
+        $config = \OC::$server->get(\OCP\IConfig::class);
663
+        if (!defined('PHPUNIT_RUN')) {
664
+            OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
665
+            $debug = $config->getSystemValue('debug', false);
666
+            OC\Log\ErrorHandler::register($debug);
667
+        }
668
+
669
+        /** @var \OC\AppFramework\Bootstrap\Coordinator $bootstrapCoordinator */
670
+        $bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
671
+        $bootstrapCoordinator->runInitialRegistration();
672
+
673
+        $eventLogger->start('init_session', 'Initialize session');
674
+        OC_App::loadApps(['session']);
675
+        if (!self::$CLI) {
676
+            self::initSession();
677
+        }
678
+        $eventLogger->end('init_session');
679
+        self::checkConfig();
680
+        self::checkInstalled($systemConfig);
681
+
682
+        OC_Response::addSecurityHeaders();
683
+
684
+        self::performSameSiteCookieProtection($config);
685
+
686
+        if (!defined('OC_CONSOLE')) {
687
+            $errors = OC_Util::checkServer($systemConfig);
688
+            if (count($errors) > 0) {
689
+                if (!self::$CLI) {
690
+                    http_response_code(503);
691
+                    OC_Util::addStyle('guest');
692
+                    try {
693
+                        OC_Template::printGuestPage('', 'error', ['errors' => $errors]);
694
+                        exit;
695
+                    } catch (\Exception $e) {
696
+                        // In case any error happens when showing the error page, we simply fall back to posting the text.
697
+                        // This might be the case when e.g. the data directory is broken and we can not load/write SCSS to/from it.
698
+                    }
699
+                }
700
+
701
+                // Convert l10n string into regular string for usage in database
702
+                $staticErrors = [];
703
+                foreach ($errors as $error) {
704
+                    echo $error['error'] . "\n";
705
+                    echo $error['hint'] . "\n\n";
706
+                    $staticErrors[] = [
707
+                        'error' => (string)$error['error'],
708
+                        'hint' => (string)$error['hint'],
709
+                    ];
710
+                }
711
+
712
+                try {
713
+                    $config->setAppValue('core', 'cronErrors', json_encode($staticErrors));
714
+                } catch (\Exception $e) {
715
+                    echo('Writing to database failed');
716
+                }
717
+                exit(1);
718
+            } elseif (self::$CLI && $config->getSystemValue('installed', false)) {
719
+                $config->deleteAppValue('core', 'cronErrors');
720
+            }
721
+        }
722
+
723
+        // User and Groups
724
+        if (!$systemConfig->getValue("installed", false)) {
725
+            self::$server->getSession()->set('user_id', '');
726
+        }
727
+
728
+        OC_User::useBackend(new \OC\User\Database());
729
+        \OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
730
+
731
+        // Subscribe to the hook
732
+        \OCP\Util::connectHook(
733
+            '\OCA\Files_Sharing\API\Server2Server',
734
+            'preLoginNameUsedAsUserName',
735
+            '\OC\User\Database',
736
+            'preLoginNameUsedAsUserName'
737
+        );
738
+
739
+        //setup extra user backends
740
+        if (!\OCP\Util::needUpgrade()) {
741
+            OC_User::setupBackends();
742
+        } else {
743
+            // Run upgrades in incognito mode
744
+            OC_User::setIncognitoMode(true);
745
+        }
746
+
747
+        self::registerCleanupHooks($systemConfig);
748
+        self::registerShareHooks($systemConfig);
749
+        self::registerEncryptionWrapperAndHooks();
750
+        self::registerAccountHooks();
751
+        self::registerResourceCollectionHooks();
752
+        self::registerFileReferenceEventListener();
753
+        self::registerAppRestrictionsHooks();
754
+
755
+        // Make sure that the application class is not loaded before the database is setup
756
+        if ($systemConfig->getValue("installed", false)) {
757
+            OC_App::loadApp('settings');
758
+            /* Build core application to make sure that listeners are registered */
759
+            self::$server->get(\OC\Core\Application::class);
760
+        }
761
+
762
+        //make sure temporary files are cleaned up
763
+        $tmpManager = \OC::$server->getTempManager();
764
+        register_shutdown_function([$tmpManager, 'clean']);
765
+        $lockProvider = \OC::$server->getLockingProvider();
766
+        register_shutdown_function([$lockProvider, 'releaseAll']);
767
+
768
+        // Check whether the sample configuration has been copied
769
+        if ($systemConfig->getValue('copied_sample_config', false)) {
770
+            $l = \OC::$server->getL10N('lib');
771
+            OC_Template::printErrorPage(
772
+                $l->t('Sample configuration detected'),
773
+                $l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php'),
774
+                503
775
+            );
776
+            return;
777
+        }
778
+
779
+        $request = \OC::$server->getRequest();
780
+        $host = $request->getInsecureServerHost();
781
+        /**
782
+         * if the host passed in headers isn't trusted
783
+         * FIXME: Should not be in here at all :see_no_evil:
784
+         */
785
+        if (!OC::$CLI
786
+            && !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
787
+            && $config->getSystemValue('installed', false)
788
+        ) {
789
+            // Allow access to CSS resources
790
+            $isScssRequest = false;
791
+            if (strpos($request->getPathInfo(), '/css/') === 0) {
792
+                $isScssRequest = true;
793
+            }
794
+
795
+            if (substr($request->getRequestUri(), -11) === '/status.php') {
796
+                http_response_code(400);
797
+                header('Content-Type: application/json');
798
+                echo '{"error": "Trusted domain error.", "code": 15}';
799
+                exit();
800
+            }
801
+
802
+            if (!$isScssRequest) {
803
+                http_response_code(400);
804
+
805
+                \OC::$server->getLogger()->warning(
806
+                    'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
807
+                    [
808
+                        'app' => 'core',
809
+                        'remoteAddress' => $request->getRemoteAddress(),
810
+                        'host' => $host,
811
+                    ]
812
+                );
813
+
814
+                $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
815
+                $tmpl->assign('docUrl', \OC::$server->getURLGenerator()->linkToDocs('admin-trusted-domains'));
816
+                $tmpl->printPage();
817
+
818
+                exit();
819
+            }
820
+        }
821
+        $eventLogger->end('boot');
822
+        $eventLogger->log('init', 'OC::init', $loaderStart, microtime(true));
823
+        $eventLogger->start('runtime', 'Runtime');
824
+        $eventLogger->start('request', 'Full request after boot');
825
+        register_shutdown_function(function () use ($eventLogger) {
826
+            $eventLogger->end('request');
827
+        });
828
+    }
829
+
830
+    /**
831
+     * register hooks for the cleanup of cache and bruteforce protection
832
+     */
833
+    public static function registerCleanupHooks(\OC\SystemConfig $systemConfig) {
834
+        //don't try to do this before we are properly setup
835
+        if ($systemConfig->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
836
+
837
+            // NOTE: This will be replaced to use OCP
838
+            $userSession = self::$server->getUserSession();
839
+            $userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
840
+                if (!defined('PHPUNIT_RUN') && $userSession->isLoggedIn()) {
841
+                    // reset brute force delay for this IP address and username
842
+                    $uid = \OC::$server->getUserSession()->getUser()->getUID();
843
+                    $request = \OC::$server->getRequest();
844
+                    $throttler = \OC::$server->getBruteForceThrottler();
845
+                    $throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
846
+                }
847
+
848
+                try {
849
+                    $cache = new \OC\Cache\File();
850
+                    $cache->gc();
851
+                } catch (\OC\ServerNotAvailableException $e) {
852
+                    // not a GC exception, pass it on
853
+                    throw $e;
854
+                } catch (\OC\ForbiddenException $e) {
855
+                    // filesystem blocked for this request, ignore
856
+                } catch (\Exception $e) {
857
+                    // a GC exception should not prevent users from using OC,
858
+                    // so log the exception
859
+                    \OC::$server->getLogger()->logException($e, [
860
+                        'message' => 'Exception when running cache gc.',
861
+                        'level' => ILogger::WARN,
862
+                        'app' => 'core',
863
+                    ]);
864
+                }
865
+            });
866
+        }
867
+    }
868
+
869
+    private static function registerEncryptionWrapperAndHooks() {
870
+        $manager = self::$server->getEncryptionManager();
871
+        \OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
872
+
873
+        $enabled = $manager->isEnabled();
874
+        if ($enabled) {
875
+            \OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
876
+            \OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
877
+            \OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
878
+            \OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
879
+        }
880
+    }
881
+
882
+    private static function registerAccountHooks() {
883
+        /** @var IEventDispatcher $dispatcher */
884
+        $dispatcher = \OC::$server->get(IEventDispatcher::class);
885
+        $dispatcher->addServiceListener(UserChangedEvent::class, \OC\Accounts\Hooks::class);
886
+    }
887
+
888
+    private static function registerAppRestrictionsHooks() {
889
+        /** @var \OC\Group\Manager $groupManager */
890
+        $groupManager = self::$server->query(\OCP\IGroupManager::class);
891
+        $groupManager->listen('\OC\Group', 'postDelete', function (\OCP\IGroup $group) {
892
+            $appManager = self::$server->getAppManager();
893
+            $apps = $appManager->getEnabledAppsForGroup($group);
894
+            foreach ($apps as $appId) {
895
+                $restrictions = $appManager->getAppRestriction($appId);
896
+                if (empty($restrictions)) {
897
+                    continue;
898
+                }
899
+                $key = array_search($group->getGID(), $restrictions);
900
+                unset($restrictions[$key]);
901
+                $restrictions = array_values($restrictions);
902
+                if (empty($restrictions)) {
903
+                    $appManager->disableApp($appId);
904
+                } else {
905
+                    $appManager->enableAppForGroups($appId, $restrictions);
906
+                }
907
+            }
908
+        });
909
+    }
910
+
911
+    private static function registerResourceCollectionHooks() {
912
+        \OC\Collaboration\Resources\Listener::register(Server::get(SymfonyAdapter::class), Server::get(IEventDispatcher::class));
913
+    }
914
+
915
+    private static function registerFileReferenceEventListener() {
916
+        \OC\Collaboration\Reference\File\FileReferenceEventListener::register(Server::get(IEventDispatcher::class));
917
+    }
918
+
919
+    /**
920
+     * register hooks for sharing
921
+     */
922
+    public static function registerShareHooks(\OC\SystemConfig $systemConfig) {
923
+        if ($systemConfig->getValue('installed')) {
924
+            OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
925
+            OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
926
+
927
+            /** @var IEventDispatcher $dispatcher */
928
+            $dispatcher = \OC::$server->get(IEventDispatcher::class);
929
+            $dispatcher->addServiceListener(UserRemovedEvent::class, \OC\Share20\UserRemovedListener::class);
930
+        }
931
+    }
932
+
933
+    protected static function registerAutoloaderCache(\OC\SystemConfig $systemConfig) {
934
+        // The class loader takes an optional low-latency cache, which MUST be
935
+        // namespaced. The instanceid is used for namespacing, but might be
936
+        // unavailable at this point. Furthermore, it might not be possible to
937
+        // generate an instanceid via \OC_Util::getInstanceId() because the
938
+        // config file may not be writable. As such, we only register a class
939
+        // loader cache if instanceid is available without trying to create one.
940
+        $instanceId = $systemConfig->getValue('instanceid', null);
941
+        if ($instanceId) {
942
+            try {
943
+                $memcacheFactory = \OC::$server->getMemCacheFactory();
944
+                self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
945
+            } catch (\Exception $ex) {
946
+            }
947
+        }
948
+    }
949
+
950
+    /**
951
+     * Handle the request
952
+     */
953
+    public static function handleRequest() {
954
+        \OC::$server->getEventLogger()->start('handle_request', 'Handle request');
955
+        $systemConfig = \OC::$server->getSystemConfig();
956
+
957
+        // Check if Nextcloud is installed or in maintenance (update) mode
958
+        if (!$systemConfig->getValue('installed', false)) {
959
+            \OC::$server->getSession()->clear();
960
+            $setupHelper = new OC\Setup(
961
+                $systemConfig,
962
+                \OC::$server->get(\bantu\IniGetWrapper\IniGetWrapper::class),
963
+                \OC::$server->getL10N('lib'),
964
+                \OC::$server->query(\OCP\Defaults::class),
965
+                \OC::$server->get(\Psr\Log\LoggerInterface::class),
966
+                \OC::$server->getSecureRandom(),
967
+                \OC::$server->query(\OC\Installer::class)
968
+            );
969
+            $controller = new OC\Core\Controller\SetupController($setupHelper);
970
+            $controller->run($_POST);
971
+            exit();
972
+        }
973
+
974
+        $request = \OC::$server->getRequest();
975
+        $requestPath = $request->getRawPathInfo();
976
+        if ($requestPath === '/heartbeat') {
977
+            return;
978
+        }
979
+        if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
980
+            self::checkMaintenanceMode($systemConfig);
981
+
982
+            if (\OCP\Util::needUpgrade()) {
983
+                if (function_exists('opcache_reset')) {
984
+                    opcache_reset();
985
+                }
986
+                if (!((bool) $systemConfig->getValue('maintenance', false))) {
987
+                    self::printUpgradePage($systemConfig);
988
+                    exit();
989
+                }
990
+            }
991
+        }
992
+
993
+        // emergency app disabling
994
+        if ($requestPath === '/disableapp'
995
+            && $request->getMethod() === 'POST'
996
+            && ((array)$request->getParam('appid')) !== ''
997
+        ) {
998
+            \OC_JSON::callCheck();
999
+            \OC_JSON::checkAdminUser();
1000
+            $appIds = (array)$request->getParam('appid');
1001
+            foreach ($appIds as $appId) {
1002
+                $appId = \OC_App::cleanAppId($appId);
1003
+                \OC::$server->getAppManager()->disableApp($appId);
1004
+            }
1005
+            \OC_JSON::success();
1006
+            exit();
1007
+        }
1008
+
1009
+        // Always load authentication apps
1010
+        OC_App::loadApps(['authentication']);
1011
+
1012
+        // Load minimum set of apps
1013
+        if (!\OCP\Util::needUpgrade()
1014
+            && !((bool) $systemConfig->getValue('maintenance', false))) {
1015
+            // For logged-in users: Load everything
1016
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1017
+                OC_App::loadApps();
1018
+            } else {
1019
+                // For guests: Load only filesystem and logging
1020
+                OC_App::loadApps(['filesystem', 'logging']);
1021
+
1022
+                // Don't try to login when a client is trying to get a OAuth token.
1023
+                // OAuth needs to support basic auth too, so the login is not valid
1024
+                // inside Nextcloud and the Login exception would ruin it.
1025
+                if ($request->getRawPathInfo() !== '/apps/oauth2/api/v1/token') {
1026
+                    self::handleLogin($request);
1027
+                }
1028
+            }
1029
+        }
1030
+
1031
+        if (!self::$CLI) {
1032
+            try {
1033
+                if (!((bool) $systemConfig->getValue('maintenance', false)) && !\OCP\Util::needUpgrade()) {
1034
+                    OC_App::loadApps(['filesystem', 'logging']);
1035
+                    OC_App::loadApps();
1036
+                }
1037
+                OC::$server->get(\OC\Route\Router::class)->match($request->getRawPathInfo());
1038
+                return;
1039
+            } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
1040
+                //header('HTTP/1.0 404 Not Found');
1041
+            } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
1042
+                http_response_code(405);
1043
+                return;
1044
+            }
1045
+        }
1046
+
1047
+        // Handle WebDAV
1048
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
1049
+            // not allowed any more to prevent people
1050
+            // mounting this root directly.
1051
+            // Users need to mount remote.php/webdav instead.
1052
+            http_response_code(405);
1053
+            return;
1054
+        }
1055
+
1056
+        // Handle requests for JSON or XML
1057
+        $acceptHeader = $request->getHeader('Accept');
1058
+        if (in_array($acceptHeader, ['application/json', 'application/xml'], true)) {
1059
+            http_response_code(404);
1060
+            return;
1061
+        }
1062
+
1063
+        // Handle resources that can't be found
1064
+        // This prevents browsers from redirecting to the default page and then
1065
+        // attempting to parse HTML as CSS and similar.
1066
+        $destinationHeader = $request->getHeader('Sec-Fetch-Dest');
1067
+        if (in_array($destinationHeader, ['font', 'script', 'style'])) {
1068
+            http_response_code(404);
1069
+            return;
1070
+        }
1071
+
1072
+        // Someone is logged in
1073
+        if (\OC::$server->getUserSession()->isLoggedIn()) {
1074
+            OC_App::loadApps();
1075
+            OC_User::setupBackends();
1076
+            OC_Util::setupFS();
1077
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToDefaultPageUrl());
1078
+        } else {
1079
+            // Not handled and not logged in
1080
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1081
+        }
1082
+    }
1083
+
1084
+    /**
1085
+     * Check login: apache auth, auth token, basic auth
1086
+     *
1087
+     * @param OCP\IRequest $request
1088
+     * @return boolean
1089
+     */
1090
+    public static function handleLogin(OCP\IRequest $request) {
1091
+        $userSession = self::$server->getUserSession();
1092
+        if (OC_User::handleApacheAuth()) {
1093
+            return true;
1094
+        }
1095
+        if ($userSession->tryTokenLogin($request)) {
1096
+            return true;
1097
+        }
1098
+        if (isset($_COOKIE['nc_username'])
1099
+            && isset($_COOKIE['nc_token'])
1100
+            && isset($_COOKIE['nc_session_id'])
1101
+            && $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1102
+            return true;
1103
+        }
1104
+        if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1105
+            return true;
1106
+        }
1107
+        return false;
1108
+    }
1109
+
1110
+    protected static function handleAuthHeaders() {
1111
+        //copy http auth headers for apache+php-fcgid work around
1112
+        if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1113
+            $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1114
+        }
1115
+
1116
+        // Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1117
+        $vars = [
1118
+            'HTTP_AUTHORIZATION', // apache+php-cgi work around
1119
+            'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1120
+        ];
1121
+        foreach ($vars as $var) {
1122
+            if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1123
+                $credentials = explode(':', base64_decode($matches[1]), 2);
1124
+                if (count($credentials) === 2) {
1125
+                    $_SERVER['PHP_AUTH_USER'] = $credentials[0];
1126
+                    $_SERVER['PHP_AUTH_PW'] = $credentials[1];
1127
+                    break;
1128
+                }
1129
+            }
1130
+        }
1131
+    }
1132 1132
 }
1133 1133
 
1134 1134
 OC::init();
Please login to merge, or discard this patch.
lib/private/Files/Filesystem.php 1 patch
Indentation   +745 added lines, -745 removed lines patch added patch discarded remove patch
@@ -50,749 +50,749 @@
 block discarded – undo
50 50
 
51 51
 class Filesystem {
52 52
 
53
-	/**
54
-	 * @var Mount\Manager $mounts
55
-	 */
56
-	private static $mounts;
57
-
58
-	public static $loaded = false;
59
-	/**
60
-	 * @var \OC\Files\View $defaultInstance
61
-	 */
62
-	private static $defaultInstance;
63
-
64
-	private static $usersSetup = [];
65
-
66
-	private static $normalizedPathCache = null;
67
-
68
-	private static $listeningForProviders = false;
69
-
70
-	/** @var string[]|null */
71
-	private static $blacklist = null;
72
-
73
-	/**
74
-	 * classname which used for hooks handling
75
-	 * used as signalclass in OC_Hooks::emit()
76
-	 */
77
-	public const CLASSNAME = 'OC_Filesystem';
78
-
79
-	/**
80
-	 * signalname emitted before file renaming
81
-	 *
82
-	 * @param string $oldpath
83
-	 * @param string $newpath
84
-	 */
85
-	public const signal_rename = 'rename';
86
-
87
-	/**
88
-	 * signal emitted after file renaming
89
-	 *
90
-	 * @param string $oldpath
91
-	 * @param string $newpath
92
-	 */
93
-	public const signal_post_rename = 'post_rename';
94
-
95
-	/**
96
-	 * signal emitted before file/dir creation
97
-	 *
98
-	 * @param string $path
99
-	 * @param bool $run changing this flag to false in hook handler will cancel event
100
-	 */
101
-	public const signal_create = 'create';
102
-
103
-	/**
104
-	 * signal emitted after file/dir creation
105
-	 *
106
-	 * @param string $path
107
-	 * @param bool $run changing this flag to false in hook handler will cancel event
108
-	 */
109
-	public const signal_post_create = 'post_create';
110
-
111
-	/**
112
-	 * signal emits before file/dir copy
113
-	 *
114
-	 * @param string $oldpath
115
-	 * @param string $newpath
116
-	 * @param bool $run changing this flag to false in hook handler will cancel event
117
-	 */
118
-	public const signal_copy = 'copy';
119
-
120
-	/**
121
-	 * signal emits after file/dir copy
122
-	 *
123
-	 * @param string $oldpath
124
-	 * @param string $newpath
125
-	 */
126
-	public const signal_post_copy = 'post_copy';
127
-
128
-	/**
129
-	 * signal emits before file/dir save
130
-	 *
131
-	 * @param string $path
132
-	 * @param bool $run changing this flag to false in hook handler will cancel event
133
-	 */
134
-	public const signal_write = 'write';
135
-
136
-	/**
137
-	 * signal emits after file/dir save
138
-	 *
139
-	 * @param string $path
140
-	 */
141
-	public const signal_post_write = 'post_write';
142
-
143
-	/**
144
-	 * signal emitted before file/dir update
145
-	 *
146
-	 * @param string $path
147
-	 * @param bool $run changing this flag to false in hook handler will cancel event
148
-	 */
149
-	public const signal_update = 'update';
150
-
151
-	/**
152
-	 * signal emitted after file/dir update
153
-	 *
154
-	 * @param string $path
155
-	 * @param bool $run changing this flag to false in hook handler will cancel event
156
-	 */
157
-	public const signal_post_update = 'post_update';
158
-
159
-	/**
160
-	 * signal emits when reading file/dir
161
-	 *
162
-	 * @param string $path
163
-	 */
164
-	public const signal_read = 'read';
165
-
166
-	/**
167
-	 * signal emits when removing file/dir
168
-	 *
169
-	 * @param string $path
170
-	 */
171
-	public const signal_delete = 'delete';
172
-
173
-	/**
174
-	 * parameters definitions for signals
175
-	 */
176
-	public const signal_param_path = 'path';
177
-	public const signal_param_oldpath = 'oldpath';
178
-	public const signal_param_newpath = 'newpath';
179
-
180
-	/**
181
-	 * run - changing this flag to false in hook handler will cancel event
182
-	 */
183
-	public const signal_param_run = 'run';
184
-
185
-	public const signal_create_mount = 'create_mount';
186
-	public const signal_delete_mount = 'delete_mount';
187
-	public const signal_param_mount_type = 'mounttype';
188
-	public const signal_param_users = 'users';
189
-
190
-	/**
191
-	 * @var \OC\Files\Storage\StorageFactory $loader
192
-	 */
193
-	private static $loader;
194
-
195
-	/** @var bool */
196
-	private static $logWarningWhenAddingStorageWrapper = true;
197
-
198
-	/**
199
-	 * @param bool $shouldLog
200
-	 * @return bool previous value
201
-	 * @internal
202
-	 */
203
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
204
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
205
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
206
-		return $previousValue;
207
-	}
208
-
209
-	/**
210
-	 * @param string $wrapperName
211
-	 * @param callable $wrapper
212
-	 * @param int $priority
213
-	 */
214
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
215
-		if (self::$logWarningWhenAddingStorageWrapper) {
216
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
217
-				'wrapper' => $wrapperName,
218
-				'app' => 'filesystem',
219
-			]);
220
-		}
221
-
222
-		$mounts = self::getMountManager()->getAll();
223
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
224
-			// do not re-wrap if storage with this name already existed
225
-			return;
226
-		}
227
-	}
228
-
229
-	/**
230
-	 * Returns the storage factory
231
-	 *
232
-	 * @return IStorageFactory
233
-	 */
234
-	public static function getLoader() {
235
-		if (!self::$loader) {
236
-			self::$loader = \OC::$server->query(IStorageFactory::class);
237
-		}
238
-		return self::$loader;
239
-	}
240
-
241
-	/**
242
-	 * Returns the mount manager
243
-	 *
244
-	 * @return \OC\Files\Mount\Manager
245
-	 */
246
-	public static function getMountManager($user = '') {
247
-		self::initMountManager();
248
-		return self::$mounts;
249
-	}
250
-
251
-	/**
252
-	 * get the mountpoint of the storage object for a path
253
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
254
-	 * returned mountpoint is relative to the absolute root of the filesystem
255
-	 * and doesn't take the chroot into account )
256
-	 *
257
-	 * @param string $path
258
-	 * @return string
259
-	 */
260
-	public static function getMountPoint($path) {
261
-		if (!self::$mounts) {
262
-			\OC_Util::setupFS();
263
-		}
264
-		$mount = self::$mounts->find($path);
265
-		return $mount->getMountPoint();
266
-	}
267
-
268
-	/**
269
-	 * get a list of all mount points in a directory
270
-	 *
271
-	 * @param string $path
272
-	 * @return string[]
273
-	 */
274
-	public static function getMountPoints($path) {
275
-		if (!self::$mounts) {
276
-			\OC_Util::setupFS();
277
-		}
278
-		$result = [];
279
-		$mounts = self::$mounts->findIn($path);
280
-		foreach ($mounts as $mount) {
281
-			$result[] = $mount->getMountPoint();
282
-		}
283
-		return $result;
284
-	}
285
-
286
-	/**
287
-	 * get the storage mounted at $mountPoint
288
-	 *
289
-	 * @param string $mountPoint
290
-	 * @return \OC\Files\Storage\Storage|null
291
-	 */
292
-	public static function getStorage($mountPoint) {
293
-		$mount = self::getMountManager()->find($mountPoint);
294
-		return $mount->getStorage();
295
-	}
296
-
297
-	/**
298
-	 * @param string $id
299
-	 * @return Mount\MountPoint[]
300
-	 */
301
-	public static function getMountByStorageId($id) {
302
-		return self::getMountManager()->findByStorageId($id);
303
-	}
304
-
305
-	/**
306
-	 * @param int $id
307
-	 * @return Mount\MountPoint[]
308
-	 */
309
-	public static function getMountByNumericId($id) {
310
-		return self::getMountManager()->findByNumericId($id);
311
-	}
312
-
313
-	/**
314
-	 * resolve a path to a storage and internal path
315
-	 *
316
-	 * @param string $path
317
-	 * @return array an array consisting of the storage and the internal path
318
-	 */
319
-	public static function resolvePath($path) {
320
-		$mount = self::getMountManager()->find($path);
321
-		return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
322
-	}
323
-
324
-	public static function init($user, $root) {
325
-		if (self::$defaultInstance) {
326
-			return false;
327
-		}
328
-		self::initInternal($root);
329
-
330
-		//load custom mount config
331
-		self::initMountPoints($user);
332
-
333
-		return true;
334
-	}
335
-
336
-	public static function initInternal($root) {
337
-		if (self::$defaultInstance) {
338
-			return false;
339
-		}
340
-		self::getLoader();
341
-		self::$defaultInstance = new View($root);
342
-		/** @var IEventDispatcher $eventDispatcher */
343
-		$eventDispatcher = \OC::$server->get(IEventDispatcher::class);
344
-		$eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
345
-			self::$defaultInstance = null;
346
-			self::$usersSetup = [];
347
-			self::$loaded = false;
348
-		});
349
-
350
-		if (!self::$mounts) {
351
-			self::$mounts = \OC::$server->getMountManager();
352
-		}
353
-
354
-		self::$loaded = true;
355
-
356
-		return true;
357
-	}
358
-
359
-	public static function initMountManager() {
360
-		if (!self::$mounts) {
361
-			self::$mounts = \OC::$server->getMountManager();
362
-		}
363
-	}
364
-
365
-	/**
366
-	 * Initialize system and personal mount points for a user
367
-	 *
368
-	 * @param string|IUser|null $user
369
-	 * @throws \OC\User\NoUserException if the user is not available
370
-	 */
371
-	public static function initMountPoints($user = '') {
372
-		/** @var IUserManager $userManager */
373
-		$userManager = \OC::$server->get(IUserManager::class);
374
-
375
-		$userObject = ($user instanceof IUser) ? $user : $userManager->get($user);
376
-		if ($userObject) {
377
-			/** @var SetupManager $setupManager */
378
-			$setupManager = \OC::$server->get(SetupManager::class);
379
-			$setupManager->setupForUser($userObject);
380
-		} else {
381
-			throw new NoUserException();
382
-		}
383
-	}
384
-
385
-	/**
386
-	 * get the default filesystem view
387
-	 *
388
-	 * @return View
389
-	 */
390
-	public static function getView() {
391
-		if (!self::$defaultInstance) {
392
-			/** @var IUserSession $session */
393
-			$session = \OC::$server->get(IUserSession::class);
394
-			$user = $session->getUser();
395
-			if ($user) {
396
-				$userDir = '/' . $user->getUID() . '/files';
397
-				self::initInternal($userDir);
398
-			}
399
-		}
400
-		return self::$defaultInstance;
401
-	}
402
-
403
-	/**
404
-	 * tear down the filesystem, removing all storage providers
405
-	 */
406
-	public static function tearDown() {
407
-		\OC_Util::tearDownFS();
408
-	}
409
-
410
-	/**
411
-	 * get the relative path of the root data directory for the current user
412
-	 *
413
-	 * @return string
414
-	 *
415
-	 * Returns path like /admin/files
416
-	 */
417
-	public static function getRoot() {
418
-		if (!self::$defaultInstance) {
419
-			return null;
420
-		}
421
-		return self::$defaultInstance->getRoot();
422
-	}
423
-
424
-	/**
425
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
426
-	 *
427
-	 * @param \OC\Files\Storage\Storage|string $class
428
-	 * @param array $arguments
429
-	 * @param string $mountpoint
430
-	 */
431
-	public static function mount($class, $arguments, $mountpoint) {
432
-		if (!self::$mounts) {
433
-			\OC_Util::setupFS();
434
-		}
435
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
436
-		self::$mounts->addMount($mount);
437
-	}
438
-
439
-	/**
440
-	 * return the path to a local version of the file
441
-	 * we need this because we can't know if a file is stored local or not from
442
-	 * outside the filestorage and for some purposes a local file is needed
443
-	 *
444
-	 * @param string $path
445
-	 * @return string
446
-	 */
447
-	public static function getLocalFile($path) {
448
-		return self::$defaultInstance->getLocalFile($path);
449
-	}
450
-
451
-	/**
452
-	 * @param string $path
453
-	 * @return string
454
-	 */
455
-	public static function getLocalFolder($path) {
456
-		return self::$defaultInstance->getLocalFolder($path);
457
-	}
458
-
459
-	/**
460
-	 * return path to file which reflects one visible in browser
461
-	 *
462
-	 * @param string $path
463
-	 * @return string
464
-	 */
465
-	public static function getLocalPath($path) {
466
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
467
-		$newpath = $path;
468
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
469
-			$newpath = substr($path, strlen($datadir));
470
-		}
471
-		return $newpath;
472
-	}
473
-
474
-	/**
475
-	 * check if the requested path is valid
476
-	 *
477
-	 * @param string $path
478
-	 * @return bool
479
-	 */
480
-	public static function isValidPath($path) {
481
-		$path = self::normalizePath($path);
482
-		if (!$path || $path[0] !== '/') {
483
-			$path = '/' . $path;
484
-		}
485
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
486
-			return false;
487
-		}
488
-		return true;
489
-	}
490
-
491
-	/**
492
-	 * @param string $filename
493
-	 * @return bool
494
-	 */
495
-	public static function isFileBlacklisted($filename) {
496
-		$filename = self::normalizePath($filename);
497
-
498
-		if (self::$blacklist === null) {
499
-			self::$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
500
-		}
501
-
502
-		$filename = strtolower(basename($filename));
503
-		return in_array($filename, self::$blacklist);
504
-	}
505
-
506
-	/**
507
-	 * check if the directory should be ignored when scanning
508
-	 * NOTE: the special directories . and .. would cause never ending recursion
509
-	 *
510
-	 * @param string $dir
511
-	 * @return boolean
512
-	 */
513
-	public static function isIgnoredDir($dir) {
514
-		if ($dir === '.' || $dir === '..') {
515
-			return true;
516
-		}
517
-		return false;
518
-	}
519
-
520
-	/**
521
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
522
-	 */
523
-	public static function mkdir($path) {
524
-		return self::$defaultInstance->mkdir($path);
525
-	}
526
-
527
-	public static function rmdir($path) {
528
-		return self::$defaultInstance->rmdir($path);
529
-	}
530
-
531
-	public static function is_dir($path) {
532
-		return self::$defaultInstance->is_dir($path);
533
-	}
534
-
535
-	public static function is_file($path) {
536
-		return self::$defaultInstance->is_file($path);
537
-	}
538
-
539
-	public static function stat($path) {
540
-		return self::$defaultInstance->stat($path);
541
-	}
542
-
543
-	public static function filetype($path) {
544
-		return self::$defaultInstance->filetype($path);
545
-	}
546
-
547
-	public static function filesize($path) {
548
-		return self::$defaultInstance->filesize($path);
549
-	}
550
-
551
-	public static function readfile($path) {
552
-		return self::$defaultInstance->readfile($path);
553
-	}
554
-
555
-	public static function isCreatable($path) {
556
-		return self::$defaultInstance->isCreatable($path);
557
-	}
558
-
559
-	public static function isReadable($path) {
560
-		return self::$defaultInstance->isReadable($path);
561
-	}
562
-
563
-	public static function isUpdatable($path) {
564
-		return self::$defaultInstance->isUpdatable($path);
565
-	}
566
-
567
-	public static function isDeletable($path) {
568
-		return self::$defaultInstance->isDeletable($path);
569
-	}
570
-
571
-	public static function isSharable($path) {
572
-		return self::$defaultInstance->isSharable($path);
573
-	}
574
-
575
-	public static function file_exists($path) {
576
-		return self::$defaultInstance->file_exists($path);
577
-	}
578
-
579
-	public static function filemtime($path) {
580
-		return self::$defaultInstance->filemtime($path);
581
-	}
582
-
583
-	public static function touch($path, $mtime = null) {
584
-		return self::$defaultInstance->touch($path, $mtime);
585
-	}
586
-
587
-	/**
588
-	 * @return string
589
-	 */
590
-	public static function file_get_contents($path) {
591
-		return self::$defaultInstance->file_get_contents($path);
592
-	}
593
-
594
-	public static function file_put_contents($path, $data) {
595
-		return self::$defaultInstance->file_put_contents($path, $data);
596
-	}
597
-
598
-	public static function unlink($path) {
599
-		return self::$defaultInstance->unlink($path);
600
-	}
601
-
602
-	public static function rename($path1, $path2) {
603
-		return self::$defaultInstance->rename($path1, $path2);
604
-	}
605
-
606
-	public static function copy($path1, $path2) {
607
-		return self::$defaultInstance->copy($path1, $path2);
608
-	}
609
-
610
-	public static function fopen($path, $mode) {
611
-		return self::$defaultInstance->fopen($path, $mode);
612
-	}
613
-
614
-	/**
615
-	 * @return string
616
-	 */
617
-	public static function toTmpFile($path) {
618
-		return self::$defaultInstance->toTmpFile($path);
619
-	}
620
-
621
-	public static function fromTmpFile($tmpFile, $path) {
622
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
623
-	}
624
-
625
-	public static function getMimeType($path) {
626
-		return self::$defaultInstance->getMimeType($path);
627
-	}
628
-
629
-	public static function hash($type, $path, $raw = false) {
630
-		return self::$defaultInstance->hash($type, $path, $raw);
631
-	}
632
-
633
-	public static function free_space($path = '/') {
634
-		return self::$defaultInstance->free_space($path);
635
-	}
636
-
637
-	public static function search($query) {
638
-		return self::$defaultInstance->search($query);
639
-	}
640
-
641
-	/**
642
-	 * @param string $query
643
-	 */
644
-	public static function searchByMime($query) {
645
-		return self::$defaultInstance->searchByMime($query);
646
-	}
647
-
648
-	/**
649
-	 * @param string|int $tag name or tag id
650
-	 * @param string $userId owner of the tags
651
-	 * @return FileInfo[] array or file info
652
-	 */
653
-	public static function searchByTag($tag, $userId) {
654
-		return self::$defaultInstance->searchByTag($tag, $userId);
655
-	}
656
-
657
-	/**
658
-	 * check if a file or folder has been updated since $time
659
-	 *
660
-	 * @param string $path
661
-	 * @param int $time
662
-	 * @return bool
663
-	 */
664
-	public static function hasUpdated($path, $time) {
665
-		return self::$defaultInstance->hasUpdated($path, $time);
666
-	}
667
-
668
-	/**
669
-	 * Fix common problems with a file path
670
-	 *
671
-	 * @param string $path
672
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
673
-	 * @param bool $isAbsolutePath whether the given path is absolute
674
-	 * @param bool $keepUnicode true to disable unicode normalization
675
-	 * @return string
676
-	 */
677
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
678
-		/**
679
-		 * FIXME: This is a workaround for existing classes and files which call
680
-		 *        this function with another type than a valid string. This
681
-		 *        conversion should get removed as soon as all existing
682
-		 *        function calls have been fixed.
683
-		 */
684
-		$path = (string)$path;
685
-
686
-		if ($path === '') {
687
-			return '/';
688
-		}
689
-
690
-		if (is_null(self::$normalizedPathCache)) {
691
-			self::$normalizedPathCache = new CappedMemoryCache(2048);
692
-		}
693
-
694
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
695
-
696
-		if ($cacheKey && isset(self::$normalizedPathCache[$cacheKey])) {
697
-			return self::$normalizedPathCache[$cacheKey];
698
-		}
699
-
700
-		//normalize unicode if possible
701
-		if (!$keepUnicode) {
702
-			$path = \OC_Util::normalizeUnicode($path);
703
-		}
704
-
705
-		//add leading slash, if it is already there we strip it anyway
706
-		$path = '/' . $path;
707
-
708
-		$patterns = [
709
-			'#\\\\#s',       // no windows style '\\' slashes
710
-			'#/\.(/\.)*/#s', // remove '/./'
711
-			'#\//+#s',       // remove sequence of slashes
712
-			'#/\.$#s',       // remove trailing '/.'
713
-		];
714
-
715
-		do {
716
-			$count = 0;
717
-			$path = preg_replace($patterns, '/', $path, -1, $count);
718
-		} while ($count > 0);
719
-
720
-		//remove trailing slash
721
-		if ($stripTrailingSlash && strlen($path) > 1) {
722
-			$path = rtrim($path, '/');
723
-		}
724
-
725
-		self::$normalizedPathCache[$cacheKey] = $path;
726
-
727
-		return $path;
728
-	}
729
-
730
-	/**
731
-	 * get the filesystem info
732
-	 *
733
-	 * @param string $path
734
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
735
-	 * defaults to true
736
-	 * @return \OC\Files\FileInfo|false False if file does not exist
737
-	 */
738
-	public static function getFileInfo($path, $includeMountPoints = true) {
739
-		return self::getView()->getFileInfo($path, $includeMountPoints);
740
-	}
741
-
742
-	/**
743
-	 * change file metadata
744
-	 *
745
-	 * @param string $path
746
-	 * @param array $data
747
-	 * @return int
748
-	 *
749
-	 * returns the fileid of the updated file
750
-	 */
751
-	public static function putFileInfo($path, $data) {
752
-		return self::$defaultInstance->putFileInfo($path, $data);
753
-	}
754
-
755
-	/**
756
-	 * get the content of a directory
757
-	 *
758
-	 * @param string $directory path under datadirectory
759
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
760
-	 * @return \OC\Files\FileInfo[]
761
-	 */
762
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
763
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
764
-	}
765
-
766
-	/**
767
-	 * Get the path of a file by id
768
-	 *
769
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
770
-	 *
771
-	 * @param int $id
772
-	 * @throws NotFoundException
773
-	 * @return string
774
-	 */
775
-	public static function getPath($id) {
776
-		return self::$defaultInstance->getPath($id);
777
-	}
778
-
779
-	/**
780
-	 * Get the owner for a file or folder
781
-	 *
782
-	 * @param string $path
783
-	 * @return string
784
-	 */
785
-	public static function getOwner($path) {
786
-		return self::$defaultInstance->getOwner($path);
787
-	}
788
-
789
-	/**
790
-	 * get the ETag for a file or folder
791
-	 *
792
-	 * @param string $path
793
-	 * @return string
794
-	 */
795
-	public static function getETag($path) {
796
-		return self::$defaultInstance->getETag($path);
797
-	}
53
+    /**
54
+     * @var Mount\Manager $mounts
55
+     */
56
+    private static $mounts;
57
+
58
+    public static $loaded = false;
59
+    /**
60
+     * @var \OC\Files\View $defaultInstance
61
+     */
62
+    private static $defaultInstance;
63
+
64
+    private static $usersSetup = [];
65
+
66
+    private static $normalizedPathCache = null;
67
+
68
+    private static $listeningForProviders = false;
69
+
70
+    /** @var string[]|null */
71
+    private static $blacklist = null;
72
+
73
+    /**
74
+     * classname which used for hooks handling
75
+     * used as signalclass in OC_Hooks::emit()
76
+     */
77
+    public const CLASSNAME = 'OC_Filesystem';
78
+
79
+    /**
80
+     * signalname emitted before file renaming
81
+     *
82
+     * @param string $oldpath
83
+     * @param string $newpath
84
+     */
85
+    public const signal_rename = 'rename';
86
+
87
+    /**
88
+     * signal emitted after file renaming
89
+     *
90
+     * @param string $oldpath
91
+     * @param string $newpath
92
+     */
93
+    public const signal_post_rename = 'post_rename';
94
+
95
+    /**
96
+     * signal emitted before file/dir creation
97
+     *
98
+     * @param string $path
99
+     * @param bool $run changing this flag to false in hook handler will cancel event
100
+     */
101
+    public const signal_create = 'create';
102
+
103
+    /**
104
+     * signal emitted after file/dir creation
105
+     *
106
+     * @param string $path
107
+     * @param bool $run changing this flag to false in hook handler will cancel event
108
+     */
109
+    public const signal_post_create = 'post_create';
110
+
111
+    /**
112
+     * signal emits before file/dir copy
113
+     *
114
+     * @param string $oldpath
115
+     * @param string $newpath
116
+     * @param bool $run changing this flag to false in hook handler will cancel event
117
+     */
118
+    public const signal_copy = 'copy';
119
+
120
+    /**
121
+     * signal emits after file/dir copy
122
+     *
123
+     * @param string $oldpath
124
+     * @param string $newpath
125
+     */
126
+    public const signal_post_copy = 'post_copy';
127
+
128
+    /**
129
+     * signal emits before file/dir save
130
+     *
131
+     * @param string $path
132
+     * @param bool $run changing this flag to false in hook handler will cancel event
133
+     */
134
+    public const signal_write = 'write';
135
+
136
+    /**
137
+     * signal emits after file/dir save
138
+     *
139
+     * @param string $path
140
+     */
141
+    public const signal_post_write = 'post_write';
142
+
143
+    /**
144
+     * signal emitted before file/dir update
145
+     *
146
+     * @param string $path
147
+     * @param bool $run changing this flag to false in hook handler will cancel event
148
+     */
149
+    public const signal_update = 'update';
150
+
151
+    /**
152
+     * signal emitted after file/dir update
153
+     *
154
+     * @param string $path
155
+     * @param bool $run changing this flag to false in hook handler will cancel event
156
+     */
157
+    public const signal_post_update = 'post_update';
158
+
159
+    /**
160
+     * signal emits when reading file/dir
161
+     *
162
+     * @param string $path
163
+     */
164
+    public const signal_read = 'read';
165
+
166
+    /**
167
+     * signal emits when removing file/dir
168
+     *
169
+     * @param string $path
170
+     */
171
+    public const signal_delete = 'delete';
172
+
173
+    /**
174
+     * parameters definitions for signals
175
+     */
176
+    public const signal_param_path = 'path';
177
+    public const signal_param_oldpath = 'oldpath';
178
+    public const signal_param_newpath = 'newpath';
179
+
180
+    /**
181
+     * run - changing this flag to false in hook handler will cancel event
182
+     */
183
+    public const signal_param_run = 'run';
184
+
185
+    public const signal_create_mount = 'create_mount';
186
+    public const signal_delete_mount = 'delete_mount';
187
+    public const signal_param_mount_type = 'mounttype';
188
+    public const signal_param_users = 'users';
189
+
190
+    /**
191
+     * @var \OC\Files\Storage\StorageFactory $loader
192
+     */
193
+    private static $loader;
194
+
195
+    /** @var bool */
196
+    private static $logWarningWhenAddingStorageWrapper = true;
197
+
198
+    /**
199
+     * @param bool $shouldLog
200
+     * @return bool previous value
201
+     * @internal
202
+     */
203
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
204
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
205
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
206
+        return $previousValue;
207
+    }
208
+
209
+    /**
210
+     * @param string $wrapperName
211
+     * @param callable $wrapper
212
+     * @param int $priority
213
+     */
214
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
215
+        if (self::$logWarningWhenAddingStorageWrapper) {
216
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
217
+                'wrapper' => $wrapperName,
218
+                'app' => 'filesystem',
219
+            ]);
220
+        }
221
+
222
+        $mounts = self::getMountManager()->getAll();
223
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
224
+            // do not re-wrap if storage with this name already existed
225
+            return;
226
+        }
227
+    }
228
+
229
+    /**
230
+     * Returns the storage factory
231
+     *
232
+     * @return IStorageFactory
233
+     */
234
+    public static function getLoader() {
235
+        if (!self::$loader) {
236
+            self::$loader = \OC::$server->query(IStorageFactory::class);
237
+        }
238
+        return self::$loader;
239
+    }
240
+
241
+    /**
242
+     * Returns the mount manager
243
+     *
244
+     * @return \OC\Files\Mount\Manager
245
+     */
246
+    public static function getMountManager($user = '') {
247
+        self::initMountManager();
248
+        return self::$mounts;
249
+    }
250
+
251
+    /**
252
+     * get the mountpoint of the storage object for a path
253
+     * ( note: because a storage is not always mounted inside the fakeroot, the
254
+     * returned mountpoint is relative to the absolute root of the filesystem
255
+     * and doesn't take the chroot into account )
256
+     *
257
+     * @param string $path
258
+     * @return string
259
+     */
260
+    public static function getMountPoint($path) {
261
+        if (!self::$mounts) {
262
+            \OC_Util::setupFS();
263
+        }
264
+        $mount = self::$mounts->find($path);
265
+        return $mount->getMountPoint();
266
+    }
267
+
268
+    /**
269
+     * get a list of all mount points in a directory
270
+     *
271
+     * @param string $path
272
+     * @return string[]
273
+     */
274
+    public static function getMountPoints($path) {
275
+        if (!self::$mounts) {
276
+            \OC_Util::setupFS();
277
+        }
278
+        $result = [];
279
+        $mounts = self::$mounts->findIn($path);
280
+        foreach ($mounts as $mount) {
281
+            $result[] = $mount->getMountPoint();
282
+        }
283
+        return $result;
284
+    }
285
+
286
+    /**
287
+     * get the storage mounted at $mountPoint
288
+     *
289
+     * @param string $mountPoint
290
+     * @return \OC\Files\Storage\Storage|null
291
+     */
292
+    public static function getStorage($mountPoint) {
293
+        $mount = self::getMountManager()->find($mountPoint);
294
+        return $mount->getStorage();
295
+    }
296
+
297
+    /**
298
+     * @param string $id
299
+     * @return Mount\MountPoint[]
300
+     */
301
+    public static function getMountByStorageId($id) {
302
+        return self::getMountManager()->findByStorageId($id);
303
+    }
304
+
305
+    /**
306
+     * @param int $id
307
+     * @return Mount\MountPoint[]
308
+     */
309
+    public static function getMountByNumericId($id) {
310
+        return self::getMountManager()->findByNumericId($id);
311
+    }
312
+
313
+    /**
314
+     * resolve a path to a storage and internal path
315
+     *
316
+     * @param string $path
317
+     * @return array an array consisting of the storage and the internal path
318
+     */
319
+    public static function resolvePath($path) {
320
+        $mount = self::getMountManager()->find($path);
321
+        return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
322
+    }
323
+
324
+    public static function init($user, $root) {
325
+        if (self::$defaultInstance) {
326
+            return false;
327
+        }
328
+        self::initInternal($root);
329
+
330
+        //load custom mount config
331
+        self::initMountPoints($user);
332
+
333
+        return true;
334
+    }
335
+
336
+    public static function initInternal($root) {
337
+        if (self::$defaultInstance) {
338
+            return false;
339
+        }
340
+        self::getLoader();
341
+        self::$defaultInstance = new View($root);
342
+        /** @var IEventDispatcher $eventDispatcher */
343
+        $eventDispatcher = \OC::$server->get(IEventDispatcher::class);
344
+        $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
345
+            self::$defaultInstance = null;
346
+            self::$usersSetup = [];
347
+            self::$loaded = false;
348
+        });
349
+
350
+        if (!self::$mounts) {
351
+            self::$mounts = \OC::$server->getMountManager();
352
+        }
353
+
354
+        self::$loaded = true;
355
+
356
+        return true;
357
+    }
358
+
359
+    public static function initMountManager() {
360
+        if (!self::$mounts) {
361
+            self::$mounts = \OC::$server->getMountManager();
362
+        }
363
+    }
364
+
365
+    /**
366
+     * Initialize system and personal mount points for a user
367
+     *
368
+     * @param string|IUser|null $user
369
+     * @throws \OC\User\NoUserException if the user is not available
370
+     */
371
+    public static function initMountPoints($user = '') {
372
+        /** @var IUserManager $userManager */
373
+        $userManager = \OC::$server->get(IUserManager::class);
374
+
375
+        $userObject = ($user instanceof IUser) ? $user : $userManager->get($user);
376
+        if ($userObject) {
377
+            /** @var SetupManager $setupManager */
378
+            $setupManager = \OC::$server->get(SetupManager::class);
379
+            $setupManager->setupForUser($userObject);
380
+        } else {
381
+            throw new NoUserException();
382
+        }
383
+    }
384
+
385
+    /**
386
+     * get the default filesystem view
387
+     *
388
+     * @return View
389
+     */
390
+    public static function getView() {
391
+        if (!self::$defaultInstance) {
392
+            /** @var IUserSession $session */
393
+            $session = \OC::$server->get(IUserSession::class);
394
+            $user = $session->getUser();
395
+            if ($user) {
396
+                $userDir = '/' . $user->getUID() . '/files';
397
+                self::initInternal($userDir);
398
+            }
399
+        }
400
+        return self::$defaultInstance;
401
+    }
402
+
403
+    /**
404
+     * tear down the filesystem, removing all storage providers
405
+     */
406
+    public static function tearDown() {
407
+        \OC_Util::tearDownFS();
408
+    }
409
+
410
+    /**
411
+     * get the relative path of the root data directory for the current user
412
+     *
413
+     * @return string
414
+     *
415
+     * Returns path like /admin/files
416
+     */
417
+    public static function getRoot() {
418
+        if (!self::$defaultInstance) {
419
+            return null;
420
+        }
421
+        return self::$defaultInstance->getRoot();
422
+    }
423
+
424
+    /**
425
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
426
+     *
427
+     * @param \OC\Files\Storage\Storage|string $class
428
+     * @param array $arguments
429
+     * @param string $mountpoint
430
+     */
431
+    public static function mount($class, $arguments, $mountpoint) {
432
+        if (!self::$mounts) {
433
+            \OC_Util::setupFS();
434
+        }
435
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
436
+        self::$mounts->addMount($mount);
437
+    }
438
+
439
+    /**
440
+     * return the path to a local version of the file
441
+     * we need this because we can't know if a file is stored local or not from
442
+     * outside the filestorage and for some purposes a local file is needed
443
+     *
444
+     * @param string $path
445
+     * @return string
446
+     */
447
+    public static function getLocalFile($path) {
448
+        return self::$defaultInstance->getLocalFile($path);
449
+    }
450
+
451
+    /**
452
+     * @param string $path
453
+     * @return string
454
+     */
455
+    public static function getLocalFolder($path) {
456
+        return self::$defaultInstance->getLocalFolder($path);
457
+    }
458
+
459
+    /**
460
+     * return path to file which reflects one visible in browser
461
+     *
462
+     * @param string $path
463
+     * @return string
464
+     */
465
+    public static function getLocalPath($path) {
466
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
467
+        $newpath = $path;
468
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
469
+            $newpath = substr($path, strlen($datadir));
470
+        }
471
+        return $newpath;
472
+    }
473
+
474
+    /**
475
+     * check if the requested path is valid
476
+     *
477
+     * @param string $path
478
+     * @return bool
479
+     */
480
+    public static function isValidPath($path) {
481
+        $path = self::normalizePath($path);
482
+        if (!$path || $path[0] !== '/') {
483
+            $path = '/' . $path;
484
+        }
485
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
486
+            return false;
487
+        }
488
+        return true;
489
+    }
490
+
491
+    /**
492
+     * @param string $filename
493
+     * @return bool
494
+     */
495
+    public static function isFileBlacklisted($filename) {
496
+        $filename = self::normalizePath($filename);
497
+
498
+        if (self::$blacklist === null) {
499
+            self::$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
500
+        }
501
+
502
+        $filename = strtolower(basename($filename));
503
+        return in_array($filename, self::$blacklist);
504
+    }
505
+
506
+    /**
507
+     * check if the directory should be ignored when scanning
508
+     * NOTE: the special directories . and .. would cause never ending recursion
509
+     *
510
+     * @param string $dir
511
+     * @return boolean
512
+     */
513
+    public static function isIgnoredDir($dir) {
514
+        if ($dir === '.' || $dir === '..') {
515
+            return true;
516
+        }
517
+        return false;
518
+    }
519
+
520
+    /**
521
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
522
+     */
523
+    public static function mkdir($path) {
524
+        return self::$defaultInstance->mkdir($path);
525
+    }
526
+
527
+    public static function rmdir($path) {
528
+        return self::$defaultInstance->rmdir($path);
529
+    }
530
+
531
+    public static function is_dir($path) {
532
+        return self::$defaultInstance->is_dir($path);
533
+    }
534
+
535
+    public static function is_file($path) {
536
+        return self::$defaultInstance->is_file($path);
537
+    }
538
+
539
+    public static function stat($path) {
540
+        return self::$defaultInstance->stat($path);
541
+    }
542
+
543
+    public static function filetype($path) {
544
+        return self::$defaultInstance->filetype($path);
545
+    }
546
+
547
+    public static function filesize($path) {
548
+        return self::$defaultInstance->filesize($path);
549
+    }
550
+
551
+    public static function readfile($path) {
552
+        return self::$defaultInstance->readfile($path);
553
+    }
554
+
555
+    public static function isCreatable($path) {
556
+        return self::$defaultInstance->isCreatable($path);
557
+    }
558
+
559
+    public static function isReadable($path) {
560
+        return self::$defaultInstance->isReadable($path);
561
+    }
562
+
563
+    public static function isUpdatable($path) {
564
+        return self::$defaultInstance->isUpdatable($path);
565
+    }
566
+
567
+    public static function isDeletable($path) {
568
+        return self::$defaultInstance->isDeletable($path);
569
+    }
570
+
571
+    public static function isSharable($path) {
572
+        return self::$defaultInstance->isSharable($path);
573
+    }
574
+
575
+    public static function file_exists($path) {
576
+        return self::$defaultInstance->file_exists($path);
577
+    }
578
+
579
+    public static function filemtime($path) {
580
+        return self::$defaultInstance->filemtime($path);
581
+    }
582
+
583
+    public static function touch($path, $mtime = null) {
584
+        return self::$defaultInstance->touch($path, $mtime);
585
+    }
586
+
587
+    /**
588
+     * @return string
589
+     */
590
+    public static function file_get_contents($path) {
591
+        return self::$defaultInstance->file_get_contents($path);
592
+    }
593
+
594
+    public static function file_put_contents($path, $data) {
595
+        return self::$defaultInstance->file_put_contents($path, $data);
596
+    }
597
+
598
+    public static function unlink($path) {
599
+        return self::$defaultInstance->unlink($path);
600
+    }
601
+
602
+    public static function rename($path1, $path2) {
603
+        return self::$defaultInstance->rename($path1, $path2);
604
+    }
605
+
606
+    public static function copy($path1, $path2) {
607
+        return self::$defaultInstance->copy($path1, $path2);
608
+    }
609
+
610
+    public static function fopen($path, $mode) {
611
+        return self::$defaultInstance->fopen($path, $mode);
612
+    }
613
+
614
+    /**
615
+     * @return string
616
+     */
617
+    public static function toTmpFile($path) {
618
+        return self::$defaultInstance->toTmpFile($path);
619
+    }
620
+
621
+    public static function fromTmpFile($tmpFile, $path) {
622
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
623
+    }
624
+
625
+    public static function getMimeType($path) {
626
+        return self::$defaultInstance->getMimeType($path);
627
+    }
628
+
629
+    public static function hash($type, $path, $raw = false) {
630
+        return self::$defaultInstance->hash($type, $path, $raw);
631
+    }
632
+
633
+    public static function free_space($path = '/') {
634
+        return self::$defaultInstance->free_space($path);
635
+    }
636
+
637
+    public static function search($query) {
638
+        return self::$defaultInstance->search($query);
639
+    }
640
+
641
+    /**
642
+     * @param string $query
643
+     */
644
+    public static function searchByMime($query) {
645
+        return self::$defaultInstance->searchByMime($query);
646
+    }
647
+
648
+    /**
649
+     * @param string|int $tag name or tag id
650
+     * @param string $userId owner of the tags
651
+     * @return FileInfo[] array or file info
652
+     */
653
+    public static function searchByTag($tag, $userId) {
654
+        return self::$defaultInstance->searchByTag($tag, $userId);
655
+    }
656
+
657
+    /**
658
+     * check if a file or folder has been updated since $time
659
+     *
660
+     * @param string $path
661
+     * @param int $time
662
+     * @return bool
663
+     */
664
+    public static function hasUpdated($path, $time) {
665
+        return self::$defaultInstance->hasUpdated($path, $time);
666
+    }
667
+
668
+    /**
669
+     * Fix common problems with a file path
670
+     *
671
+     * @param string $path
672
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
673
+     * @param bool $isAbsolutePath whether the given path is absolute
674
+     * @param bool $keepUnicode true to disable unicode normalization
675
+     * @return string
676
+     */
677
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
678
+        /**
679
+         * FIXME: This is a workaround for existing classes and files which call
680
+         *        this function with another type than a valid string. This
681
+         *        conversion should get removed as soon as all existing
682
+         *        function calls have been fixed.
683
+         */
684
+        $path = (string)$path;
685
+
686
+        if ($path === '') {
687
+            return '/';
688
+        }
689
+
690
+        if (is_null(self::$normalizedPathCache)) {
691
+            self::$normalizedPathCache = new CappedMemoryCache(2048);
692
+        }
693
+
694
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
695
+
696
+        if ($cacheKey && isset(self::$normalizedPathCache[$cacheKey])) {
697
+            return self::$normalizedPathCache[$cacheKey];
698
+        }
699
+
700
+        //normalize unicode if possible
701
+        if (!$keepUnicode) {
702
+            $path = \OC_Util::normalizeUnicode($path);
703
+        }
704
+
705
+        //add leading slash, if it is already there we strip it anyway
706
+        $path = '/' . $path;
707
+
708
+        $patterns = [
709
+            '#\\\\#s',       // no windows style '\\' slashes
710
+            '#/\.(/\.)*/#s', // remove '/./'
711
+            '#\//+#s',       // remove sequence of slashes
712
+            '#/\.$#s',       // remove trailing '/.'
713
+        ];
714
+
715
+        do {
716
+            $count = 0;
717
+            $path = preg_replace($patterns, '/', $path, -1, $count);
718
+        } while ($count > 0);
719
+
720
+        //remove trailing slash
721
+        if ($stripTrailingSlash && strlen($path) > 1) {
722
+            $path = rtrim($path, '/');
723
+        }
724
+
725
+        self::$normalizedPathCache[$cacheKey] = $path;
726
+
727
+        return $path;
728
+    }
729
+
730
+    /**
731
+     * get the filesystem info
732
+     *
733
+     * @param string $path
734
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
735
+     * defaults to true
736
+     * @return \OC\Files\FileInfo|false False if file does not exist
737
+     */
738
+    public static function getFileInfo($path, $includeMountPoints = true) {
739
+        return self::getView()->getFileInfo($path, $includeMountPoints);
740
+    }
741
+
742
+    /**
743
+     * change file metadata
744
+     *
745
+     * @param string $path
746
+     * @param array $data
747
+     * @return int
748
+     *
749
+     * returns the fileid of the updated file
750
+     */
751
+    public static function putFileInfo($path, $data) {
752
+        return self::$defaultInstance->putFileInfo($path, $data);
753
+    }
754
+
755
+    /**
756
+     * get the content of a directory
757
+     *
758
+     * @param string $directory path under datadirectory
759
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
760
+     * @return \OC\Files\FileInfo[]
761
+     */
762
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
763
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
764
+    }
765
+
766
+    /**
767
+     * Get the path of a file by id
768
+     *
769
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
770
+     *
771
+     * @param int $id
772
+     * @throws NotFoundException
773
+     * @return string
774
+     */
775
+    public static function getPath($id) {
776
+        return self::$defaultInstance->getPath($id);
777
+    }
778
+
779
+    /**
780
+     * Get the owner for a file or folder
781
+     *
782
+     * @param string $path
783
+     * @return string
784
+     */
785
+    public static function getOwner($path) {
786
+        return self::$defaultInstance->getOwner($path);
787
+    }
788
+
789
+    /**
790
+     * get the ETag for a file or folder
791
+     *
792
+     * @param string $path
793
+     * @return string
794
+     */
795
+    public static function getETag($path) {
796
+        return self::$defaultInstance->getETag($path);
797
+    }
798 798
 }
Please login to merge, or discard this patch.