Completed
Push — master ( 8f6386...12d32e )
by
unknown
43:18 queued 02:50
created
tests/lib/UtilTest.php 1 patch
Indentation   +317 added lines, -317 removed lines patch added patch discarded remove patch
@@ -17,321 +17,321 @@
 block discarded – undo
17 17
  * @group DB
18 18
  */
19 19
 class UtilTest extends \Test\TestCase {
20
-	public function testGetVersion(): void {
21
-		$version = Util::getVersion();
22
-		$this->assertTrue(is_array($version));
23
-		foreach ($version as $num) {
24
-			$this->assertTrue(is_int($num));
25
-		}
26
-	}
27
-
28
-	public function testSanitizeHTML(): void {
29
-		$badArray = [
30
-			'While it is unusual to pass an array',
31
-			'this function actually <blink>supports</blink> it.',
32
-			'And therefore there needs to be a <script>alert("Unit"+\'test\')</script> for it!',
33
-			[
34
-				'And It Even May <strong>Nest</strong>',
35
-			],
36
-		];
37
-		$goodArray = [
38
-			'While it is unusual to pass an array',
39
-			'this function actually &lt;blink&gt;supports&lt;/blink&gt; it.',
40
-			'And therefore there needs to be a &lt;script&gt;alert(&quot;Unit&quot;+&#039;test&#039;)&lt;/script&gt; for it!',
41
-			[
42
-				'And It Even May &lt;strong&gt;Nest&lt;/strong&gt;'
43
-			],
44
-		];
45
-		$result = OC_Util::sanitizeHTML($badArray);
46
-		$this->assertEquals($goodArray, $result);
47
-
48
-		$badString = '<img onload="alert(1)" />';
49
-		$result = OC_Util::sanitizeHTML($badString);
50
-		$this->assertEquals('&lt;img onload=&quot;alert(1)&quot; /&gt;', $result);
51
-
52
-		$badString = "<script>alert('Hacked!');</script>";
53
-		$result = OC_Util::sanitizeHTML($badString);
54
-		$this->assertEquals('&lt;script&gt;alert(&#039;Hacked!&#039;);&lt;/script&gt;', $result);
55
-
56
-		$goodString = 'This is a good string without HTML.';
57
-		$result = OC_Util::sanitizeHTML($goodString);
58
-		$this->assertEquals('This is a good string without HTML.', $result);
59
-	}
60
-
61
-	public function testEncodePath(): void {
62
-		$component = '/§#@test%&^ä/-child';
63
-		$result = OC_Util::encodePath($component);
64
-		$this->assertEquals('/%C2%A7%23%40test%25%26%5E%C3%A4/-child', $result);
65
-	}
66
-
67
-	public function testIsNonUTF8Locale(): void {
68
-		// OC_Util::isNonUTF8Locale() assumes escapeshellcmd('§') returns '' with non-UTF-8 locale.
69
-		$locale = setlocale(LC_CTYPE, 0);
70
-		setlocale(LC_CTYPE, 'C');
71
-		$this->assertEquals('', escapeshellcmd('§'));
72
-		$this->assertEquals('\'\'', escapeshellarg('§'));
73
-		setlocale(LC_CTYPE, 'C.UTF-8');
74
-		$this->assertEquals('§', escapeshellcmd('§'));
75
-		$this->assertEquals('\'§\'', escapeshellarg('§'));
76
-		setlocale(LC_CTYPE, $locale);
77
-	}
78
-
79
-	public function testFileInfoLoaded(): void {
80
-		$expected = function_exists('finfo_open');
81
-		$this->assertEquals($expected, \OC_Util::fileInfoLoaded());
82
-	}
83
-
84
-	/**
85
-	 * Host is "localhost" this is a valid for emails,
86
-	 * but not for default strict email verification that requires a top level domain.
87
-	 * So we check that with strict email verification we fallback to the default
88
-	 */
89
-	public function testGetDefaultEmailAddressStrict(): void {
90
-		$email = Util::getDefaultEmailAddress('no-reply');
91
-		$this->assertEquals('[email protected]', $email);
92
-	}
93
-
94
-	/**
95
-	 * If no strict email check is enabled "localhost" should validate as a valid email domain
96
-	 */
97
-	public function testGetDefaultEmailAddress(): void {
98
-		$config = \OC::$server->getConfig();
99
-		$config->setAppValue('core', 'enforce_strict_email_check', 'no');
100
-		$email = Util::getDefaultEmailAddress('no-reply');
101
-		$this->assertEquals('no-reply@localhost', $email);
102
-		$config->deleteAppValue('core', 'enforce_strict_email_check');
103
-	}
104
-
105
-	public function testGetDefaultEmailAddressFromConfig(): void {
106
-		$config = \OC::$server->getConfig();
107
-		$config->setSystemValue('mail_domain', 'example.com');
108
-		$email = Util::getDefaultEmailAddress('no-reply');
109
-		$this->assertEquals('[email protected]', $email);
110
-		$config->deleteSystemValue('mail_domain');
111
-	}
112
-
113
-	public function testGetConfiguredEmailAddressFromConfig(): void {
114
-		$config = \OC::$server->getConfig();
115
-		$config->setSystemValue('mail_domain', 'example.com');
116
-		$config->setSystemValue('mail_from_address', 'owncloud');
117
-		$email = Util::getDefaultEmailAddress('no-reply');
118
-		$this->assertEquals('[email protected]', $email);
119
-		$config->deleteSystemValue('mail_domain');
120
-		$config->deleteSystemValue('mail_from_address');
121
-	}
122
-
123
-	public function testGetInstanceIdGeneratesValidId(): void {
124
-		\OC::$server->getConfig()->deleteSystemValue('instanceid');
125
-		$instanceId = OC_Util::getInstanceId();
126
-		$this->assertStringStartsWith('oc', $instanceId);
127
-		$matchesRegex = preg_match('/^[a-z0-9]+$/', $instanceId);
128
-		$this->assertSame(1, $matchesRegex);
129
-	}
130
-
131
-	/**
132
-	 * Test needUpgrade() when the core version is increased
133
-	 */
134
-	public function testNeedUpgradeCore(): void {
135
-		$config = \OC::$server->getConfig();
136
-		$oldConfigVersion = $config->getSystemValue('version', '0.0.0');
137
-		$oldSessionVersion = \OC::$server->getSession()->get('OC_Version');
138
-
139
-		$this->assertFalse(Util::needUpgrade());
140
-
141
-		$config->setSystemValue('version', '7.0.0.0');
142
-		\OC::$server->getSession()->set('OC_Version', [7, 0, 0, 1]);
143
-		self::invokePrivate(new Util, 'needUpgradeCache', [null]);
144
-
145
-		$this->assertTrue(Util::needUpgrade());
146
-
147
-		$config->setSystemValue('version', $oldConfigVersion);
148
-		\OC::$server->getSession()->set('OC_Version', $oldSessionVersion);
149
-		self::invokePrivate(new Util, 'needUpgradeCache', [null]);
150
-
151
-		$this->assertFalse(Util::needUpgrade());
152
-	}
153
-
154
-	public function testCheckDataDirectoryValidity(): void {
155
-		$dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
156
-		touch($dataDir . '/.ncdata');
157
-		$errors = \OC_Util::checkDataDirectoryValidity($dataDir);
158
-		$this->assertEmpty($errors);
159
-		\OCP\Files::rmdirr($dataDir);
160
-
161
-		$dataDir = \OC::$server->getTempManager()->getTemporaryFolder();
162
-		// no touch
163
-		$errors = \OC_Util::checkDataDirectoryValidity($dataDir);
164
-		$this->assertNotEmpty($errors);
165
-		\OCP\Files::rmdirr($dataDir);
166
-
167
-		$errors = \OC_Util::checkDataDirectoryValidity('relative/path');
168
-		$this->assertNotEmpty($errors);
169
-	}
170
-
171
-	protected function setUp(): void {
172
-		parent::setUp();
173
-
174
-		\OC_Util::$styles = [];
175
-		self::invokePrivate(Util::class, 'scripts', [[]]);
176
-		self::invokePrivate(Util::class, 'scriptDeps', [[]]);
177
-	}
178
-	protected function tearDown(): void {
179
-		parent::tearDown();
180
-
181
-		\OC_Util::$styles = [];
182
-		self::invokePrivate(Util::class, 'scripts', [[]]);
183
-		self::invokePrivate(Util::class, 'scriptDeps', [[]]);
184
-	}
185
-
186
-	public function testAddScript(): void {
187
-		Util::addScript('first', 'myFirstJSFile');
188
-		Util::addScript('core', 'myFancyJSFile1');
189
-		Util::addScript('files', 'myFancyJSFile2', 'core');
190
-		Util::addScript('myApp5', 'myApp5JSFile', 'myApp2');
191
-		Util::addScript('myApp', 'myFancyJSFile3');
192
-		Util::addScript('core', 'myFancyJSFile4');
193
-		// after itself
194
-		Util::addScript('core', 'myFancyJSFile5', 'core');
195
-		// add duplicate
196
-		Util::addScript('core', 'myFancyJSFile1');
197
-		// dependency chain
198
-		Util::addScript('myApp4', 'myApp4JSFile', 'myApp3');
199
-		Util::addScript('myApp3', 'myApp3JSFile', 'myApp2');
200
-		Util::addScript('myApp2', 'myApp2JSFile', 'myApp');
201
-		Util::addScript('core', 'common');
202
-		Util::addScript('core', 'main');
203
-
204
-		$scripts = Util::getScripts();
205
-
206
-		// Core should appear first
207
-		$this->assertEquals(
208
-			0,
209
-			array_search('core/js/common', $scripts, true)
210
-		);
211
-		$this->assertEquals(
212
-			1,
213
-			array_search('core/js/main', $scripts, true)
214
-		);
215
-		$this->assertEquals(
216
-			2,
217
-			array_search('core/js/myFancyJSFile1', $scripts, true)
218
-		);
219
-		$this->assertEquals(
220
-			3,
221
-			array_search('core/js/myFancyJSFile4', $scripts, true)
222
-		);
223
-
224
-		// Dependencies should appear before their children
225
-		$this->assertLessThan(
226
-			array_search('files/js/myFancyJSFile2', $scripts, true),
227
-			array_search('core/js/myFancyJSFile3', $scripts, true)
228
-		);
229
-		$this->assertLessThan(
230
-			array_search('myApp2/js/myApp2JSFile', $scripts, true),
231
-			array_search('myApp/js/myFancyJSFile3', $scripts, true)
232
-		);
233
-		$this->assertLessThan(
234
-			array_search('myApp3/js/myApp3JSFile', $scripts, true),
235
-			array_search('myApp2/js/myApp2JSFile', $scripts, true)
236
-		);
237
-		$this->assertLessThan(
238
-			array_search('myApp4/js/myApp4JSFile', $scripts, true),
239
-			array_search('myApp3/js/myApp3JSFile', $scripts, true)
240
-		);
241
-		$this->assertLessThan(
242
-			array_search('myApp5/js/myApp5JSFile', $scripts, true),
243
-			array_search('myApp2/js/myApp2JSFile', $scripts, true)
244
-		);
245
-
246
-		// No duplicates
247
-		$this->assertEquals(
248
-			$scripts,
249
-			array_unique($scripts)
250
-		);
251
-
252
-		// All scripts still there
253
-		$scripts = [
254
-			'core/js/common',
255
-			'core/js/main',
256
-			'core/js/myFancyJSFile1',
257
-			'core/js/myFancyJSFile4',
258
-			'core/js/myFancyJSFile5',
259
-			'first/l10n/en',
260
-			'first/js/myFirstJSFile',
261
-			'files/l10n/en',
262
-			'files/js/myFancyJSFile2',
263
-			'myApp/l10n/en',
264
-			'myApp/js/myFancyJSFile3',
265
-			'myApp2/l10n/en',
266
-			'myApp2/js/myApp2JSFile',
267
-			'myApp5/l10n/en',
268
-			'myApp5/js/myApp5JSFile',
269
-			'myApp3/l10n/en',
270
-			'myApp3/js/myApp3JSFile',
271
-			'myApp4/l10n/en',
272
-			'myApp4/js/myApp4JSFile',
273
-		];
274
-		foreach ($scripts as $script) {
275
-			$this->assertContains($script, $scripts);
276
-		}
277
-	}
278
-
279
-	public function testAddScriptCircularDependency(): void {
280
-		Util::addScript('circular', 'file1', 'dependency');
281
-		Util::addScript('dependency', 'file2', 'circular');
282
-
283
-		$scripts = Util::getScripts();
284
-		$this->assertContains('circular/js/file1', $scripts);
285
-		$this->assertContains('dependency/js/file2', $scripts);
286
-	}
287
-
288
-	public function testAddTranslations(): void {
289
-		Util::addTranslations('appId', 'de');
290
-
291
-		$this->assertEquals([
292
-			'appId/l10n/de'
293
-		], Util::getScripts());
294
-		$this->assertEquals([], \OC_Util::$styles);
295
-	}
296
-
297
-	public function testAddStyle(): void {
298
-		\OC_Util::addStyle('core', 'myFancyCSSFile1');
299
-		\OC_Util::addStyle('myApp', 'myFancyCSSFile2');
300
-		\OC_Util::addStyle('core', 'myFancyCSSFile0', true);
301
-		\OC_Util::addStyle('core', 'myFancyCSSFile10', true);
302
-		// add duplicate
303
-		\OC_Util::addStyle('core', 'myFancyCSSFile1');
304
-
305
-		$this->assertEquals([], Util::getScripts());
306
-		$this->assertEquals([
307
-			'core/css/myFancyCSSFile10',
308
-			'core/css/myFancyCSSFile0',
309
-			'core/css/myFancyCSSFile1',
310
-			'myApp/css/myFancyCSSFile2',
311
-		], \OC_Util::$styles);
312
-	}
313
-
314
-	public function testAddVendorStyle(): void {
315
-		\OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
316
-		\OC_Util::addVendorStyle('myApp', 'myFancyCSSFile2');
317
-		\OC_Util::addVendorStyle('core', 'myFancyCSSFile0', true);
318
-		\OC_Util::addVendorStyle('core', 'myFancyCSSFile10', true);
319
-		// add duplicate
320
-		\OC_Util::addVendorStyle('core', 'myFancyCSSFile1');
321
-
322
-		$this->assertEquals([], Util::getScripts());
323
-		$this->assertEquals([
324
-			'core/vendor/myFancyCSSFile10',
325
-			'core/vendor/myFancyCSSFile0',
326
-			'core/vendor/myFancyCSSFile1',
327
-			'myApp/vendor/myFancyCSSFile2',
328
-		], \OC_Util::$styles);
329
-	}
330
-
331
-	public function testShortenMultibyteString(): void {
332
-		$this->assertEquals('Short nuff', Util::shortenMultibyteString('Short nuff', 255));
333
-		$this->assertEquals('ABC', Util::shortenMultibyteString('ABCDEF', 3));
334
-		// each of the characters is 12 bytes
335
-		$this->assertEquals('
Please login to merge, or discard this patch.
lib/private/TemplateLayout.php 1 patch
Indentation   +373 added lines, -373 removed lines patch added patch discarded remove patch
@@ -35,377 +35,377 @@
 block discarded – undo
35 35
 use OCP\Util;
36 36
 
37 37
 class TemplateLayout {
38
-	private static string $versionHash = '';
39
-	/** @var string[] */
40
-	private static array $cacheBusterCache = [];
41
-
42
-	public static ?CSSResourceLocator $cssLocator = null;
43
-	public static ?JSResourceLocator $jsLocator = null;
44
-
45
-	public function __construct(
46
-		private IConfig $config,
47
-		private IAppManager $appManager,
48
-		private InitialStateService $initialState,
49
-		private INavigationManager $navigationManager,
50
-		private ITemplateManager $templateManager,
51
-		private ServerVersion $serverVersion,
52
-	) {
53
-	}
54
-
55
-	public function getPageTemplate(string $renderAs, string $appId): ITemplate {
56
-		// Add fallback theming variables if not rendered as user
57
-		if ($renderAs !== TemplateResponse::RENDER_AS_USER) {
58
-			// TODO cache generated default theme if enabled for fallback if server is erroring ?
59
-			Util::addStyle('theming', 'default');
60
-		}
61
-
62
-		// Decide which page we show
63
-		switch ($renderAs) {
64
-			case TemplateResponse::RENDER_AS_USER:
65
-				$page = $this->templateManager->getTemplate('core', 'layout.user');
66
-				if (in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
67
-					$page->assign('bodyid', 'body-settings');
68
-				} else {
69
-					$page->assign('bodyid', 'body-user');
70
-				}
71
-
72
-				$this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry());
73
-				$this->initialState->provideInitialState('core', 'apps', array_values($this->navigationManager->getAll()));
74
-
75
-				if ($this->config->getSystemValueBool('unified_search.enabled', false) || !$this->config->getSystemValueBool('enable_non-accessible_features', true)) {
76
-					$this->initialState->provideInitialState('unified-search', 'limit-default', (int)$this->config->getAppValue('core', 'unified-search.limit-default', (string)SearchQuery::LIMIT_DEFAULT));
77
-					$this->initialState->provideInitialState('unified-search', 'min-search-length', (int)$this->config->getAppValue('core', 'unified-search.min-search-length', (string)1));
78
-					$this->initialState->provideInitialState('unified-search', 'live-search', $this->config->getAppValue('core', 'unified-search.live-search', 'yes') === 'yes');
79
-					Util::addScript('core', 'legacy-unified-search', 'core');
80
-				} else {
81
-					Util::addScript('core', 'unified-search', 'core');
82
-				}
83
-				// Set body data-theme
84
-				$page->assign('enabledThemes', []);
85
-				if ($this->appManager->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) {
86
-					$themesService = Server::get(\OCA\Theming\Service\ThemesService::class);
87
-					$page->assign('enabledThemes', $themesService->getEnabledThemes());
88
-				}
89
-
90
-				// Set logo link target
91
-				$logoUrl = $this->config->getSystemValueString('logo_url', '');
92
-				$page->assign('logoUrl', $logoUrl);
93
-
94
-				// Set default entry name
95
-				$defaultEntryId = $this->navigationManager->getDefaultEntryIdForUser();
96
-				$defaultEntry = $this->navigationManager->get($defaultEntryId);
97
-				$page->assign('defaultAppName', $defaultEntry['name'] ?? '');
98
-
99
-				// Add navigation entry
100
-				$page->assign('application', '');
101
-				$page->assign('appid', $appId);
102
-
103
-				$navigation = $this->navigationManager->getAll();
104
-				$page->assign('navigation', $navigation);
105
-				$settingsNavigation = $this->navigationManager->getAll('settings');
106
-				$this->initialState->provideInitialState('core', 'settingsNavEntries', $settingsNavigation);
107
-
108
-				foreach ($navigation as $entry) {
109
-					if ($entry['active']) {
110
-						$page->assign('application', $entry['name']);
111
-						break;
112
-					}
113
-				}
114
-
115
-				foreach ($settingsNavigation as $entry) {
116
-					if ($entry['active']) {
117
-						$page->assign('application', $entry['name']);
118
-						break;
119
-					}
120
-				}
121
-
122
-				$user = Server::get(IUserSession::class)->getUser();
123
-
124
-				if ($user === null) {
125
-					$page->assign('user_uid', false);
126
-					$page->assign('user_displayname', false);
127
-					$page->assign('userAvatarSet', false);
128
-					$page->assign('userStatus', false);
129
-				} else {
130
-					$page->assign('user_uid', $user->getUID());
131
-					$page->assign('user_displayname', $user->getDisplayName());
132
-					$page->assign('userAvatarSet', true);
133
-					$page->assign('userAvatarVersion', $this->config->getUserValue($user->getUID(), 'avatar', 'version', 0));
134
-				}
135
-				break;
136
-			case TemplateResponse::RENDER_AS_ERROR:
137
-				$page = $this->templateManager->getTemplate('core', 'layout.guest', '', false);
138
-				$page->assign('bodyid', 'body-login');
139
-				$page->assign('user_displayname', '');
140
-				$page->assign('user_uid', '');
141
-				break;
142
-			case TemplateResponse::RENDER_AS_GUEST:
143
-				$page = $this->templateManager->getTemplate('core', 'layout.guest');
144
-				Util::addStyle('guest');
145
-				$page->assign('bodyid', 'body-login');
146
-
147
-				$userDisplayName = false;
148
-				$user = Server::get(IUserSession::class)->getUser();
149
-				if ($user) {
150
-					$userDisplayName = $user->getDisplayName();
151
-				}
152
-				$page->assign('user_displayname', $userDisplayName);
153
-				$page->assign('user_uid', \OC_User::getUser());
154
-				break;
155
-			case TemplateResponse::RENDER_AS_PUBLIC:
156
-				$page = $this->templateManager->getTemplate('core', 'layout.public');
157
-				$page->assign('appid', $appId);
158
-				$page->assign('bodyid', 'body-public');
159
-
160
-				// Set body data-theme
161
-				$page->assign('enabledThemes', []);
162
-				if ($this->appManager->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) {
163
-					$themesService = Server::get(\OCA\Theming\Service\ThemesService::class);
164
-					$page->assign('enabledThemes', $themesService->getEnabledThemes());
165
-				}
166
-
167
-				// Set logo link target
168
-				$logoUrl = $this->config->getSystemValueString('logo_url', '');
169
-				$page->assign('logoUrl', $logoUrl);
170
-
171
-				$subscription = Server::get(IRegistry::class);
172
-				$showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true);
173
-				if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) {
174
-					$showSimpleSignup = false;
175
-				}
176
-
177
-				$defaultSignUpLink = 'https://nextcloud.com/signup/';
178
-				$signUpLink = $this->config->getSystemValueString('registration_link', $defaultSignUpLink);
179
-				if ($signUpLink !== $defaultSignUpLink) {
180
-					$showSimpleSignup = true;
181
-				}
182
-
183
-				if ($this->appManager->isEnabledForUser('registration')) {
184
-					$urlGenerator = Server::get(IURLGenerator::class);
185
-					$signUpLink = $urlGenerator->getAbsoluteURL('/index.php/apps/registration/');
186
-				}
187
-
188
-				$page->assign('showSimpleSignUpLink', $showSimpleSignup);
189
-				$page->assign('signUpLink', $signUpLink);
190
-				break;
191
-			default:
192
-				$page = $this->templateManager->getTemplate('core', 'layout.base');
193
-				break;
194
-		}
195
-		// Send the language, locale, and direction to our layouts
196
-		$l10nFactory = Server::get(IFactory::class);
197
-		$lang = $l10nFactory->findLanguage();
198
-		$locale = $l10nFactory->findLocale($lang);
199
-		$direction = $l10nFactory->getLanguageDirection($lang);
200
-
201
-		$lang = str_replace('_', '-', $lang);
202
-		$page->assign('language', $lang);
203
-		$page->assign('locale', $locale);
204
-		$page->assign('direction', $direction);
205
-
206
-		if ($this->config->getSystemValueBool('installed', false)) {
207
-			if (empty(self::$versionHash)) {
208
-				$v = $this->appManager->getAppInstalledVersions();
209
-				$v['core'] = implode('.', $this->serverVersion->getVersion());
210
-				self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
211
-			}
212
-		} else {
213
-			self::$versionHash = md5('not installed');
214
-		}
215
-
216
-		// Add the js files
217
-		$jsFiles = self::findJavascriptFiles(Util::getScripts());
218
-		$page->assign('jsfiles', []);
219
-		if ($this->config->getSystemValueBool('installed', false) && $renderAs != TemplateResponse::RENDER_AS_ERROR) {
220
-			// this is on purpose outside of the if statement below so that the initial state is prefilled (done in the getConfig() call)
221
-			// see https://github.com/nextcloud/server/pull/22636 for details
222
-			$jsConfigHelper = new JSConfigHelper(
223
-				$this->serverVersion,
224
-				\OCP\Util::getL10N('lib'),
225
-				\OCP\Server::get(Defaults::class),
226
-				$this->appManager,
227
-				\OC::$server->getSession(),
228
-				\OC::$server->getUserSession()->getUser(),
229
-				$this->config,
230
-				\OC::$server->getGroupManager(),
231
-				\OC::$server->get(IniGetWrapper::class),
232
-				\OC::$server->getURLGenerator(),
233
-				\OC::$server->get(CapabilitiesManager::class),
234
-				\OCP\Server::get(IInitialStateService::class),
235
-				\OCP\Server::get(IProvider::class),
236
-				\OCP\Server::get(FilenameValidator::class),
237
-			);
238
-			$config = $jsConfigHelper->getConfig();
239
-			if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
240
-				$page->assign('inline_ocjs', $config);
241
-			} else {
242
-				$page->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
243
-			}
244
-		}
245
-		foreach ($jsFiles as $info) {
246
-			$web = $info[1];
247
-			$file = $info[2];
248
-			$page->append('jsfiles', $web . '/' . $file . $this->getVersionHashSuffix());
249
-		}
250
-
251
-		$request = \OCP\Server::get(IRequest::class);
252
-
253
-		try {
254
-			$pathInfo = $request->getPathInfo();
255
-		} catch (\Exception $e) {
256
-			$pathInfo = '';
257
-		}
258
-
259
-		// Do not initialise scss appdata until we have a fully installed instance
260
-		// Do not load scss for update, errors, installation or login page
261
-		if ($this->config->getSystemValueBool('installed', false)
262
-			&& !\OCP\Util::needUpgrade()
263
-			&& $pathInfo !== ''
264
-			&& !preg_match('/^\/login/', $pathInfo)
265
-			&& $renderAs !== TemplateResponse::RENDER_AS_ERROR
266
-		) {
267
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
268
-		} else {
269
-			// If we ignore the scss compiler,
270
-			// we need to load the guest css fallback
271
-			Util::addStyle('guest');
272
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
273
-		}
274
-
275
-		$page->assign('cssfiles', []);
276
-		$page->assign('printcssfiles', []);
277
-		$this->initialState->provideInitialState('core', 'versionHash', self::$versionHash);
278
-		foreach ($cssFiles as $info) {
279
-			$web = $info[1];
280
-			$file = $info[2];
281
-
282
-			if (str_ends_with($file, 'print.css')) {
283
-				$page->append('printcssfiles', $web . '/' . $file . $this->getVersionHashSuffix());
284
-			} else {
285
-				$suffix = $this->getVersionHashSuffix($web, $file);
286
-
287
-				if (!str_contains($file, '?v=')) {
288
-					$page->append('cssfiles', $web . '/' . $file . $suffix);
289
-				} else {
290
-					$page->append('cssfiles', $web . '/' . $file . '-' . substr($suffix, 3));
291
-				}
292
-			}
293
-		}
294
-
295
-		if ($request->isUserAgent([Request::USER_AGENT_CLIENT_IOS, Request::USER_AGENT_SAFARI, Request::USER_AGENT_SAFARI_MOBILE])) {
296
-			// Prevent auto zoom with iOS but still allow user zoom
297
-			// On chrome (and others) this does not work (will also disable user zoom)
298
-			$page->assign('viewport_maximum_scale', '1.0');
299
-		}
300
-
301
-		$page->assign('initialStates', $this->initialState->getInitialStates());
302
-
303
-		$page->assign('id-app-content', $renderAs === TemplateResponse::RENDER_AS_USER ? '#app-content' : '#content');
304
-		$page->assign('id-app-navigation', $renderAs === TemplateResponse::RENDER_AS_USER ? '#app-navigation' : null);
305
-
306
-		return $page;
307
-	}
308
-
309
-	protected function getVersionHashSuffix(string $path = '', string $file = ''): string {
310
-		if ($this->config->getSystemValueBool('debug', false)) {
311
-			// allows chrome workspace mapping in debug mode
312
-			return '';
313
-		}
314
-
315
-		if ($this->config->getSystemValueBool('installed', false) === false) {
316
-			// if not installed just return the version hash
317
-			return '?v=' . self::$versionHash;
318
-		}
319
-
320
-		$hash = false;
321
-		// Try the web-root first
322
-		if ($path !== '') {
323
-			$hash = $this->getVersionHashByPath($path);
324
-		}
325
-		// If not found try the file
326
-		if ($hash === false && $file !== '') {
327
-			$hash = $this->getVersionHashByPath($file);
328
-		}
329
-		// As a last resort we use the server version hash
330
-		if ($hash === false) {
331
-			$hash = self::$versionHash;
332
-		}
333
-
334
-		// The theming app is force-enabled thus the cache buster is always available
335
-		$themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
336
-
337
-		return '?v=' . $hash . $themingSuffix;
338
-	}
339
-
340
-	private function getVersionHashByPath(string $path): string|false {
341
-		if (array_key_exists($path, self::$cacheBusterCache) === false) {
342
-			// Not yet cached, so lets find the cache buster string
343
-			$appId = $this->getAppNamefromPath($path);
344
-			if ($appId === false) {
345
-				// No app Id could be guessed
346
-				return false;
347
-			}
348
-
349
-			if ($appId === 'core') {
350
-				// core is not a real app but the server itself
351
-				$hash = self::$versionHash;
352
-			} else {
353
-				$appVersion = $this->appManager->getAppVersion($appId);
354
-				// For shipped apps the app version is not a single source of truth, we rather also need to consider the Nextcloud version
355
-				if ($this->appManager->isShipped($appId)) {
356
-					$appVersion .= '-' . self::$versionHash;
357
-				}
358
-
359
-				$hash = substr(md5($appVersion), 0, 8);
360
-			}
361
-			self::$cacheBusterCache[$path] = $hash;
362
-		}
363
-
364
-		return self::$cacheBusterCache[$path];
365
-	}
366
-
367
-	public static function findStylesheetFiles(array $styles): array {
368
-		if (!self::$cssLocator) {
369
-			self::$cssLocator = \OCP\Server::get(CSSResourceLocator::class);
370
-		}
371
-		self::$cssLocator->find($styles);
372
-		return self::$cssLocator->getResources();
373
-	}
374
-
375
-	public function getAppNamefromPath(string $path): string|false {
376
-		if ($path !== '') {
377
-			$pathParts = explode('/', $path);
378
-			if ($pathParts[0] === 'css') {
379
-				// This is a scss request
380
-				return $pathParts[1];
381
-			} elseif ($pathParts[0] === 'core') {
382
-				return 'core';
383
-			}
384
-			return end($pathParts);
385
-		}
386
-		return false;
387
-	}
388
-
389
-	public static function findJavascriptFiles(array $scripts): array {
390
-		if (!self::$jsLocator) {
391
-			self::$jsLocator = \OCP\Server::get(JSResourceLocator::class);
392
-		}
393
-		self::$jsLocator->find($scripts);
394
-		return self::$jsLocator->getResources();
395
-	}
396
-
397
-	/**
398
-	 * Converts the absolute file path to a relative path from \OC::$SERVERROOT
399
-	 * @param string $filePath Absolute path
400
-	 * @return string Relative path
401
-	 * @throws \Exception If $filePath is not under \OC::$SERVERROOT
402
-	 */
403
-	public static function convertToRelativePath(string $filePath) {
404
-		$relativePath = explode(\OC::$SERVERROOT, $filePath);
405
-		if (count($relativePath) !== 2) {
406
-			throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
407
-		}
408
-
409
-		return $relativePath[1];
410
-	}
38
+    private static string $versionHash = '';
39
+    /** @var string[] */
40
+    private static array $cacheBusterCache = [];
41
+
42
+    public static ?CSSResourceLocator $cssLocator = null;
43
+    public static ?JSResourceLocator $jsLocator = null;
44
+
45
+    public function __construct(
46
+        private IConfig $config,
47
+        private IAppManager $appManager,
48
+        private InitialStateService $initialState,
49
+        private INavigationManager $navigationManager,
50
+        private ITemplateManager $templateManager,
51
+        private ServerVersion $serverVersion,
52
+    ) {
53
+    }
54
+
55
+    public function getPageTemplate(string $renderAs, string $appId): ITemplate {
56
+        // Add fallback theming variables if not rendered as user
57
+        if ($renderAs !== TemplateResponse::RENDER_AS_USER) {
58
+            // TODO cache generated default theme if enabled for fallback if server is erroring ?
59
+            Util::addStyle('theming', 'default');
60
+        }
61
+
62
+        // Decide which page we show
63
+        switch ($renderAs) {
64
+            case TemplateResponse::RENDER_AS_USER:
65
+                $page = $this->templateManager->getTemplate('core', 'layout.user');
66
+                if (in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
67
+                    $page->assign('bodyid', 'body-settings');
68
+                } else {
69
+                    $page->assign('bodyid', 'body-user');
70
+                }
71
+
72
+                $this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry());
73
+                $this->initialState->provideInitialState('core', 'apps', array_values($this->navigationManager->getAll()));
74
+
75
+                if ($this->config->getSystemValueBool('unified_search.enabled', false) || !$this->config->getSystemValueBool('enable_non-accessible_features', true)) {
76
+                    $this->initialState->provideInitialState('unified-search', 'limit-default', (int)$this->config->getAppValue('core', 'unified-search.limit-default', (string)SearchQuery::LIMIT_DEFAULT));
77
+                    $this->initialState->provideInitialState('unified-search', 'min-search-length', (int)$this->config->getAppValue('core', 'unified-search.min-search-length', (string)1));
78
+                    $this->initialState->provideInitialState('unified-search', 'live-search', $this->config->getAppValue('core', 'unified-search.live-search', 'yes') === 'yes');
79
+                    Util::addScript('core', 'legacy-unified-search', 'core');
80
+                } else {
81
+                    Util::addScript('core', 'unified-search', 'core');
82
+                }
83
+                // Set body data-theme
84
+                $page->assign('enabledThemes', []);
85
+                if ($this->appManager->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) {
86
+                    $themesService = Server::get(\OCA\Theming\Service\ThemesService::class);
87
+                    $page->assign('enabledThemes', $themesService->getEnabledThemes());
88
+                }
89
+
90
+                // Set logo link target
91
+                $logoUrl = $this->config->getSystemValueString('logo_url', '');
92
+                $page->assign('logoUrl', $logoUrl);
93
+
94
+                // Set default entry name
95
+                $defaultEntryId = $this->navigationManager->getDefaultEntryIdForUser();
96
+                $defaultEntry = $this->navigationManager->get($defaultEntryId);
97
+                $page->assign('defaultAppName', $defaultEntry['name'] ?? '');
98
+
99
+                // Add navigation entry
100
+                $page->assign('application', '');
101
+                $page->assign('appid', $appId);
102
+
103
+                $navigation = $this->navigationManager->getAll();
104
+                $page->assign('navigation', $navigation);
105
+                $settingsNavigation = $this->navigationManager->getAll('settings');
106
+                $this->initialState->provideInitialState('core', 'settingsNavEntries', $settingsNavigation);
107
+
108
+                foreach ($navigation as $entry) {
109
+                    if ($entry['active']) {
110
+                        $page->assign('application', $entry['name']);
111
+                        break;
112
+                    }
113
+                }
114
+
115
+                foreach ($settingsNavigation as $entry) {
116
+                    if ($entry['active']) {
117
+                        $page->assign('application', $entry['name']);
118
+                        break;
119
+                    }
120
+                }
121
+
122
+                $user = Server::get(IUserSession::class)->getUser();
123
+
124
+                if ($user === null) {
125
+                    $page->assign('user_uid', false);
126
+                    $page->assign('user_displayname', false);
127
+                    $page->assign('userAvatarSet', false);
128
+                    $page->assign('userStatus', false);
129
+                } else {
130
+                    $page->assign('user_uid', $user->getUID());
131
+                    $page->assign('user_displayname', $user->getDisplayName());
132
+                    $page->assign('userAvatarSet', true);
133
+                    $page->assign('userAvatarVersion', $this->config->getUserValue($user->getUID(), 'avatar', 'version', 0));
134
+                }
135
+                break;
136
+            case TemplateResponse::RENDER_AS_ERROR:
137
+                $page = $this->templateManager->getTemplate('core', 'layout.guest', '', false);
138
+                $page->assign('bodyid', 'body-login');
139
+                $page->assign('user_displayname', '');
140
+                $page->assign('user_uid', '');
141
+                break;
142
+            case TemplateResponse::RENDER_AS_GUEST:
143
+                $page = $this->templateManager->getTemplate('core', 'layout.guest');
144
+                Util::addStyle('guest');
145
+                $page->assign('bodyid', 'body-login');
146
+
147
+                $userDisplayName = false;
148
+                $user = Server::get(IUserSession::class)->getUser();
149
+                if ($user) {
150
+                    $userDisplayName = $user->getDisplayName();
151
+                }
152
+                $page->assign('user_displayname', $userDisplayName);
153
+                $page->assign('user_uid', \OC_User::getUser());
154
+                break;
155
+            case TemplateResponse::RENDER_AS_PUBLIC:
156
+                $page = $this->templateManager->getTemplate('core', 'layout.public');
157
+                $page->assign('appid', $appId);
158
+                $page->assign('bodyid', 'body-public');
159
+
160
+                // Set body data-theme
161
+                $page->assign('enabledThemes', []);
162
+                if ($this->appManager->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) {
163
+                    $themesService = Server::get(\OCA\Theming\Service\ThemesService::class);
164
+                    $page->assign('enabledThemes', $themesService->getEnabledThemes());
165
+                }
166
+
167
+                // Set logo link target
168
+                $logoUrl = $this->config->getSystemValueString('logo_url', '');
169
+                $page->assign('logoUrl', $logoUrl);
170
+
171
+                $subscription = Server::get(IRegistry::class);
172
+                $showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true);
173
+                if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) {
174
+                    $showSimpleSignup = false;
175
+                }
176
+
177
+                $defaultSignUpLink = 'https://nextcloud.com/signup/';
178
+                $signUpLink = $this->config->getSystemValueString('registration_link', $defaultSignUpLink);
179
+                if ($signUpLink !== $defaultSignUpLink) {
180
+                    $showSimpleSignup = true;
181
+                }
182
+
183
+                if ($this->appManager->isEnabledForUser('registration')) {
184
+                    $urlGenerator = Server::get(IURLGenerator::class);
185
+                    $signUpLink = $urlGenerator->getAbsoluteURL('/index.php/apps/registration/');
186
+                }
187
+
188
+                $page->assign('showSimpleSignUpLink', $showSimpleSignup);
189
+                $page->assign('signUpLink', $signUpLink);
190
+                break;
191
+            default:
192
+                $page = $this->templateManager->getTemplate('core', 'layout.base');
193
+                break;
194
+        }
195
+        // Send the language, locale, and direction to our layouts
196
+        $l10nFactory = Server::get(IFactory::class);
197
+        $lang = $l10nFactory->findLanguage();
198
+        $locale = $l10nFactory->findLocale($lang);
199
+        $direction = $l10nFactory->getLanguageDirection($lang);
200
+
201
+        $lang = str_replace('_', '-', $lang);
202
+        $page->assign('language', $lang);
203
+        $page->assign('locale', $locale);
204
+        $page->assign('direction', $direction);
205
+
206
+        if ($this->config->getSystemValueBool('installed', false)) {
207
+            if (empty(self::$versionHash)) {
208
+                $v = $this->appManager->getAppInstalledVersions();
209
+                $v['core'] = implode('.', $this->serverVersion->getVersion());
210
+                self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
211
+            }
212
+        } else {
213
+            self::$versionHash = md5('not installed');
214
+        }
215
+
216
+        // Add the js files
217
+        $jsFiles = self::findJavascriptFiles(Util::getScripts());
218
+        $page->assign('jsfiles', []);
219
+        if ($this->config->getSystemValueBool('installed', false) && $renderAs != TemplateResponse::RENDER_AS_ERROR) {
220
+            // this is on purpose outside of the if statement below so that the initial state is prefilled (done in the getConfig() call)
221
+            // see https://github.com/nextcloud/server/pull/22636 for details
222
+            $jsConfigHelper = new JSConfigHelper(
223
+                $this->serverVersion,
224
+                \OCP\Util::getL10N('lib'),
225
+                \OCP\Server::get(Defaults::class),
226
+                $this->appManager,
227
+                \OC::$server->getSession(),
228
+                \OC::$server->getUserSession()->getUser(),
229
+                $this->config,
230
+                \OC::$server->getGroupManager(),
231
+                \OC::$server->get(IniGetWrapper::class),
232
+                \OC::$server->getURLGenerator(),
233
+                \OC::$server->get(CapabilitiesManager::class),
234
+                \OCP\Server::get(IInitialStateService::class),
235
+                \OCP\Server::get(IProvider::class),
236
+                \OCP\Server::get(FilenameValidator::class),
237
+            );
238
+            $config = $jsConfigHelper->getConfig();
239
+            if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
240
+                $page->assign('inline_ocjs', $config);
241
+            } else {
242
+                $page->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
243
+            }
244
+        }
245
+        foreach ($jsFiles as $info) {
246
+            $web = $info[1];
247
+            $file = $info[2];
248
+            $page->append('jsfiles', $web . '/' . $file . $this->getVersionHashSuffix());
249
+        }
250
+
251
+        $request = \OCP\Server::get(IRequest::class);
252
+
253
+        try {
254
+            $pathInfo = $request->getPathInfo();
255
+        } catch (\Exception $e) {
256
+            $pathInfo = '';
257
+        }
258
+
259
+        // Do not initialise scss appdata until we have a fully installed instance
260
+        // Do not load scss for update, errors, installation or login page
261
+        if ($this->config->getSystemValueBool('installed', false)
262
+            && !\OCP\Util::needUpgrade()
263
+            && $pathInfo !== ''
264
+            && !preg_match('/^\/login/', $pathInfo)
265
+            && $renderAs !== TemplateResponse::RENDER_AS_ERROR
266
+        ) {
267
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
268
+        } else {
269
+            // If we ignore the scss compiler,
270
+            // we need to load the guest css fallback
271
+            Util::addStyle('guest');
272
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
273
+        }
274
+
275
+        $page->assign('cssfiles', []);
276
+        $page->assign('printcssfiles', []);
277
+        $this->initialState->provideInitialState('core', 'versionHash', self::$versionHash);
278
+        foreach ($cssFiles as $info) {
279
+            $web = $info[1];
280
+            $file = $info[2];
281
+
282
+            if (str_ends_with($file, 'print.css')) {
283
+                $page->append('printcssfiles', $web . '/' . $file . $this->getVersionHashSuffix());
284
+            } else {
285
+                $suffix = $this->getVersionHashSuffix($web, $file);
286
+
287
+                if (!str_contains($file, '?v=')) {
288
+                    $page->append('cssfiles', $web . '/' . $file . $suffix);
289
+                } else {
290
+                    $page->append('cssfiles', $web . '/' . $file . '-' . substr($suffix, 3));
291
+                }
292
+            }
293
+        }
294
+
295
+        if ($request->isUserAgent([Request::USER_AGENT_CLIENT_IOS, Request::USER_AGENT_SAFARI, Request::USER_AGENT_SAFARI_MOBILE])) {
296
+            // Prevent auto zoom with iOS but still allow user zoom
297
+            // On chrome (and others) this does not work (will also disable user zoom)
298
+            $page->assign('viewport_maximum_scale', '1.0');
299
+        }
300
+
301
+        $page->assign('initialStates', $this->initialState->getInitialStates());
302
+
303
+        $page->assign('id-app-content', $renderAs === TemplateResponse::RENDER_AS_USER ? '#app-content' : '#content');
304
+        $page->assign('id-app-navigation', $renderAs === TemplateResponse::RENDER_AS_USER ? '#app-navigation' : null);
305
+
306
+        return $page;
307
+    }
308
+
309
+    protected function getVersionHashSuffix(string $path = '', string $file = ''): string {
310
+        if ($this->config->getSystemValueBool('debug', false)) {
311
+            // allows chrome workspace mapping in debug mode
312
+            return '';
313
+        }
314
+
315
+        if ($this->config->getSystemValueBool('installed', false) === false) {
316
+            // if not installed just return the version hash
317
+            return '?v=' . self::$versionHash;
318
+        }
319
+
320
+        $hash = false;
321
+        // Try the web-root first
322
+        if ($path !== '') {
323
+            $hash = $this->getVersionHashByPath($path);
324
+        }
325
+        // If not found try the file
326
+        if ($hash === false && $file !== '') {
327
+            $hash = $this->getVersionHashByPath($file);
328
+        }
329
+        // As a last resort we use the server version hash
330
+        if ($hash === false) {
331
+            $hash = self::$versionHash;
332
+        }
333
+
334
+        // The theming app is force-enabled thus the cache buster is always available
335
+        $themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
336
+
337
+        return '?v=' . $hash . $themingSuffix;
338
+    }
339
+
340
+    private function getVersionHashByPath(string $path): string|false {
341
+        if (array_key_exists($path, self::$cacheBusterCache) === false) {
342
+            // Not yet cached, so lets find the cache buster string
343
+            $appId = $this->getAppNamefromPath($path);
344
+            if ($appId === false) {
345
+                // No app Id could be guessed
346
+                return false;
347
+            }
348
+
349
+            if ($appId === 'core') {
350
+                // core is not a real app but the server itself
351
+                $hash = self::$versionHash;
352
+            } else {
353
+                $appVersion = $this->appManager->getAppVersion($appId);
354
+                // For shipped apps the app version is not a single source of truth, we rather also need to consider the Nextcloud version
355
+                if ($this->appManager->isShipped($appId)) {
356
+                    $appVersion .= '-' . self::$versionHash;
357
+                }
358
+
359
+                $hash = substr(md5($appVersion), 0, 8);
360
+            }
361
+            self::$cacheBusterCache[$path] = $hash;
362
+        }
363
+
364
+        return self::$cacheBusterCache[$path];
365
+    }
366
+
367
+    public static function findStylesheetFiles(array $styles): array {
368
+        if (!self::$cssLocator) {
369
+            self::$cssLocator = \OCP\Server::get(CSSResourceLocator::class);
370
+        }
371
+        self::$cssLocator->find($styles);
372
+        return self::$cssLocator->getResources();
373
+    }
374
+
375
+    public function getAppNamefromPath(string $path): string|false {
376
+        if ($path !== '') {
377
+            $pathParts = explode('/', $path);
378
+            if ($pathParts[0] === 'css') {
379
+                // This is a scss request
380
+                return $pathParts[1];
381
+            } elseif ($pathParts[0] === 'core') {
382
+                return 'core';
383
+            }
384
+            return end($pathParts);
385
+        }
386
+        return false;
387
+    }
388
+
389
+    public static function findJavascriptFiles(array $scripts): array {
390
+        if (!self::$jsLocator) {
391
+            self::$jsLocator = \OCP\Server::get(JSResourceLocator::class);
392
+        }
393
+        self::$jsLocator->find($scripts);
394
+        return self::$jsLocator->getResources();
395
+    }
396
+
397
+    /**
398
+     * Converts the absolute file path to a relative path from \OC::$SERVERROOT
399
+     * @param string $filePath Absolute path
400
+     * @return string Relative path
401
+     * @throws \Exception If $filePath is not under \OC::$SERVERROOT
402
+     */
403
+    public static function convertToRelativePath(string $filePath) {
404
+        $relativePath = explode(\OC::$SERVERROOT, $filePath);
405
+        if (count($relativePath) !== 2) {
406
+            throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
407
+        }
408
+
409
+        return $relativePath[1];
410
+    }
411 411
 }
Please login to merge, or discard this patch.
lib/private/Template/functions.php 1 patch
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
  * @param string $string
18 18
  */
19 19
 function p($string): void {
20
-	print(Util::sanitizeHTML($string));
20
+    print(Util::sanitizeHTML($string));
21 21
 }
22 22
 
23 23
 /**
@@ -26,14 +26,14 @@  discard block
 block discarded – undo
26 26
  * @param string $opts, additional optional options
27 27
  */
28 28
 function emit_css_tag($href, $opts = ''): void {
29
-	$s = '<link rel="stylesheet"';
30
-	if (!empty($href)) {
31
-		$s .= ' href="' . $href . '"';
32
-	}
33
-	if (!empty($opts)) {
34
-		$s .= ' ' . $opts;
35
-	}
36
-	print_unescaped($s . ">\n");
29
+    $s = '<link rel="stylesheet"';
30
+    if (!empty($href)) {
31
+        $s .= ' href="' . $href . '"';
32
+    }
33
+    if (!empty($opts)) {
34
+        $s .= ' ' . $opts;
35
+    }
36
+    print_unescaped($s . ">\n");
37 37
 }
38 38
 
39 39
 /**
@@ -41,12 +41,12 @@  discard block
 block discarded – undo
41 41
  * @param array $obj all the script information from template
42 42
  */
43 43
 function emit_css_loading_tags($obj): void {
44
-	foreach ($obj['cssfiles'] as $css) {
45
-		emit_css_tag($css);
46
-	}
47
-	foreach ($obj['printcssfiles'] as $css) {
48
-		emit_css_tag($css, 'media="print"');
49
-	}
44
+    foreach ($obj['cssfiles'] as $css) {
45
+        emit_css_tag($css);
46
+    }
47
+    foreach ($obj['printcssfiles'] as $css) {
48
+        emit_css_tag($css, 'media="print"');
49
+    }
50 50
 }
51 51
 
52 52
 /**
@@ -56,24 +56,24 @@  discard block
 block discarded – undo
56 56
  * @param string $content_type the type of the source (e.g. 'module')
57 57
  */
58 58
 function emit_script_tag(string $src, string $script_content = '', string $content_type = ''): void {
59
-	$nonceManager = Server::get(ContentSecurityPolicyNonceManager::class);
59
+    $nonceManager = Server::get(ContentSecurityPolicyNonceManager::class);
60 60
 
61
-	$defer_str = ' defer';
62
-	$type = $content_type !== '' ? ' type="' . $content_type . '"' : '';
61
+    $defer_str = ' defer';
62
+    $type = $content_type !== '' ? ' type="' . $content_type . '"' : '';
63 63
 
64
-	$s = '<script nonce="' . $nonceManager->getNonce() . '"';
65
-	if (!empty($src)) {
66
-		// emit script tag for deferred loading from $src
67
-		$s .= $defer_str . ' src="' . $src . '"' . $type . '>';
68
-	} elseif ($script_content !== '') {
69
-		// emit script tag for inline script from $script_content without defer (see MDN)
70
-		$s .= ">\n" . $script_content . "\n";
71
-	} else {
72
-		// no $src nor $src_content, really useless empty tag
73
-		$s .= '>';
74
-	}
75
-	$s .= '</script>';
76
-	print_unescaped($s . "\n");
64
+    $s = '<script nonce="' . $nonceManager->getNonce() . '"';
65
+    if (!empty($src)) {
66
+        // emit script tag for deferred loading from $src
67
+        $s .= $defer_str . ' src="' . $src . '"' . $type . '>';
68
+    } elseif ($script_content !== '') {
69
+        // emit script tag for inline script from $script_content without defer (see MDN)
70
+        $s .= ">\n" . $script_content . "\n";
71
+    } else {
72
+        // no $src nor $src_content, really useless empty tag
73
+        $s .= '>';
74
+    }
75
+    $s .= '</script>';
76
+    print_unescaped($s . "\n");
77 77
 }
78 78
 
79 79
 /**
@@ -81,14 +81,14 @@  discard block
 block discarded – undo
81 81
  * @param array $obj all the script information from template
82 82
  */
83 83
 function emit_script_loading_tags($obj): void {
84
-	foreach ($obj['jsfiles'] as $jsfile) {
85
-		$fileName = explode('?', $jsfile, 2)[0];
86
-		$type = str_ends_with($fileName, '.mjs') ? 'module' : '';
87
-		emit_script_tag($jsfile, '', $type);
88
-	}
89
-	if (!empty($obj['inline_ocjs'])) {
90
-		emit_script_tag('', $obj['inline_ocjs']);
91
-	}
84
+    foreach ($obj['jsfiles'] as $jsfile) {
85
+        $fileName = explode('?', $jsfile, 2)[0];
86
+        $type = str_ends_with($fileName, '.mjs') ? 'module' : '';
87
+        emit_script_tag($jsfile, '', $type);
88
+    }
89
+    if (!empty($obj['inline_ocjs'])) {
90
+        emit_script_tag('', $obj['inline_ocjs']);
91
+    }
92 92
 }
93 93
 
94 94
 /**
@@ -97,7 +97,7 @@  discard block
 block discarded – undo
97 97
  * @param string $string the string which will be printed as it is
98 98
  */
99 99
 function print_unescaped($string): void {
100
-	print($string);
100
+    print($string);
101 101
 }
102 102
 
103 103
 /**
@@ -113,13 +113,13 @@  discard block
 block discarded – undo
113 113
  *                              if an array is given it will add all scripts
114 114
  */
115 115
 function script($app, $file = null): void {
116
-	if (is_array($file)) {
117
-		foreach ($file as $script) {
118
-			Util::addScript($app, $script, 'core');
119
-		}
120
-	} else {
121
-		Util::addScript($app, $file, 'core');
122
-	}
116
+    if (is_array($file)) {
117
+        foreach ($file as $script) {
118
+            Util::addScript($app, $script, 'core');
119
+        }
120
+    } else {
121
+        Util::addScript($app, $file, 'core');
122
+    }
123 123
 }
124 124
 
125 125
 /**
@@ -129,13 +129,13 @@  discard block
 block discarded – undo
129 129
  *                              if an array is given it will add all styles
130 130
  */
131 131
 function style($app, $file = null): void {
132
-	if (is_array($file)) {
133
-		foreach ($file as $f) {
134
-			OC_Util::addStyle($app, $f);
135
-		}
136
-	} else {
137
-		OC_Util::addStyle($app, $file);
138
-	}
132
+    if (is_array($file)) {
133
+        foreach ($file as $f) {
134
+            OC_Util::addStyle($app, $f);
135
+        }
136
+    } else {
137
+        OC_Util::addStyle($app, $file);
138
+    }
139 139
 }
140 140
 
141 141
 /**
@@ -145,13 +145,13 @@  discard block
 block discarded – undo
145 145
  *                              if an array is given it will add all styles
146 146
  */
147 147
 function vendor_style($app, $file = null): void {
148
-	if (is_array($file)) {
149
-		foreach ($file as $f) {
150
-			OC_Util::addVendorStyle($app, $f);
151
-		}
152
-	} else {
153
-		OC_Util::addVendorStyle($app, $file);
154
-	}
148
+    if (is_array($file)) {
149
+        foreach ($file as $f) {
150
+            OC_Util::addVendorStyle($app, $f);
151
+        }
152
+    } else {
153
+        OC_Util::addVendorStyle($app, $file);
154
+    }
155 155
 }
156 156
 
157 157
 /**
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
  *                    if an array is given it will add all styles
161 161
  */
162 162
 function translation($app): void {
163
-	Util::addTranslations($app);
163
+    Util::addTranslations($app);
164 164
 }
165 165
 
166 166
 /**
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
  * For further information have a look at \OCP\IURLGenerator::linkTo
174 174
  */
175 175
 function link_to($app, $file, $args = []) {
176
-	return Server::get(IURLGenerator::class)->linkTo($app, $file, $args);
176
+    return Server::get(IURLGenerator::class)->linkTo($app, $file, $args);
177 177
 }
178 178
 
179 179
 /**
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
  * @return string url to the online documentation
182 182
  */
183 183
 function link_to_docs($key) {
184
-	return Server::get(IURLGenerator::class)->linkToDocs($key);
184
+    return Server::get(IURLGenerator::class)->linkToDocs($key);
185 185
 }
186 186
 
187 187
 /**
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
  * For further information have a look at \OCP\IURLGenerator::imagePath
194 194
  */
195 195
 function image_path($app, $image) {
196
-	return Server::get(IURLGenerator::class)->imagePath($app, $image);
196
+    return Server::get(IURLGenerator::class)->imagePath($app, $image);
197 197
 }
198 198
 
199 199
 /**
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
  * @return string link to the image
203 203
  */
204 204
 function mimetype_icon($mimetype) {
205
-	return Server::get(IMimeTypeDetector::class)->mimeTypeIcon($mimetype);
205
+    return Server::get(IMimeTypeDetector::class)->mimeTypeIcon($mimetype);
206 206
 }
207 207
 
208 208
 /**
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
  * @return string link to the preview
213 213
  */
214 214
 function preview_icon($path) {
215
-	return Server::get(IURLGenerator::class)->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]);
215
+    return Server::get(IURLGenerator::class)->linkToRoute('core.Preview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path]);
216 216
 }
217 217
 
218 218
 /**
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
  * @return string
222 222
  */
223 223
 function publicPreview_icon($path, $token) {
224
-	return Server::get(IURLGenerator::class)->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 'token' => $token]);
224
+    return Server::get(IURLGenerator::class)->linkToRoute('files_sharing.PublicPreview.getPreview', ['x' => 32, 'y' => 32, 'file' => $path, 'token' => $token]);
225 225
 }
226 226
 
227 227
 /**
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
  * For further information have a look at Util::humanFileSize
234 234
  */
235 235
 function human_file_size($bytes) {
236
-	return Util::humanFileSize($bytes);
236
+    return Util::humanFileSize($bytes);
237 237
 }
238 238
 
239 239
 /**
@@ -242,9 +242,9 @@  discard block
 block discarded – undo
242 242
  * @return int timestamp without time value
243 243
  */
244 244
 function strip_time($timestamp) {
245
-	$date = new \DateTime("@{$timestamp}");
246
-	$date->setTime(0, 0, 0);
247
-	return (int)$date->format('U');
245
+    $date = new \DateTime("@{$timestamp}");
246
+    $date->setTime(0, 0, 0);
247
+    return (int)$date->format('U');
248 248
 }
249 249
 
250 250
 /**
@@ -256,12 +256,12 @@  discard block
 block discarded – undo
256 256
  * @return string timestamp
257 257
  */
258 258
 function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false): string {
259
-	$formatter = Server::get(IDateTimeFormatter::class);
259
+    $formatter = Server::get(IDateTimeFormatter::class);
260 260
 
261
-	if ($dateOnly) {
262
-		return $formatter->formatDateSpan($timestamp, $fromTime);
263
-	}
264
-	return $formatter->formatTimeSpan($timestamp, $fromTime);
261
+    if ($dateOnly) {
262
+        return $formatter->formatDateSpan($timestamp, $fromTime);
263
+    }
264
+    return $formatter->formatTimeSpan($timestamp, $fromTime);
265 265
 }
266 266
 
267 267
 /**
@@ -270,29 +270,29 @@  discard block
 block discarded – undo
270 270
  * @param array $params
271 271
  */
272 272
 function html_select_options($options, $selected, $params = []): string {
273
-	if (!is_array($selected)) {
274
-		$selected = [$selected];
275
-	}
276
-	if (isset($params['combine']) && $params['combine']) {
277
-		$options = array_combine($options, $options);
278
-	}
279
-	$value_name = $label_name = false;
280
-	if (isset($params['value'])) {
281
-		$value_name = $params['value'];
282
-	}
283
-	if (isset($params['label'])) {
284
-		$label_name = $params['label'];
285
-	}
286
-	$html = '';
287
-	foreach ($options as $value => $label) {
288
-		if ($value_name && is_array($label)) {
289
-			$value = $label[$value_name];
290
-		}
291
-		if ($label_name && is_array($label)) {
292
-			$label = $label[$label_name];
293
-		}
294
-		$select = in_array($value, $selected) ? ' selected="selected"' : '';
295
-		$html .= '<option value="' . Util::sanitizeHTML($value) . '"' . $select . '>' . Util::sanitizeHTML($label) . '</option>' . "\n";
296
-	}
297
-	return $html;
273
+    if (!is_array($selected)) {
274
+        $selected = [$selected];
275
+    }
276
+    if (isset($params['combine']) && $params['combine']) {
277
+        $options = array_combine($options, $options);
278
+    }
279
+    $value_name = $label_name = false;
280
+    if (isset($params['value'])) {
281
+        $value_name = $params['value'];
282
+    }
283
+    if (isset($params['label'])) {
284
+        $label_name = $params['label'];
285
+    }
286
+    $html = '';
287
+    foreach ($options as $value => $label) {
288
+        if ($value_name && is_array($label)) {
289
+            $value = $label[$value_name];
290
+        }
291
+        if ($label_name && is_array($label)) {
292
+            $label = $label[$label_name];
293
+        }
294
+        $select = in_array($value, $selected) ? ' selected="selected"' : '';
295
+        $html .= '<option value="' . Util::sanitizeHTML($value) . '"' . $select . '>' . Util::sanitizeHTML($label) . '</option>' . "\n";
296
+    }
297
+    return $html;
298 298
 }
Please login to merge, or discard this patch.
lib/private/legacy/OC_Util.php 1 patch
Indentation   +917 added lines, -917 removed lines patch added patch discarded remove patch
@@ -20,924 +20,924 @@
 block discarded – undo
20 20
 use Psr\Log\LoggerInterface;
21 21
 
22 22
 class OC_Util {
23
-	public static $styles = [];
24
-	public static $headers = [];
25
-
26
-	/** @var array Local cache of version.php */
27
-	private static $versionCache = null;
28
-
29
-	protected static function getAppManager() {
30
-		return \OC::$server->getAppManager();
31
-	}
32
-
33
-	/**
34
-	 * Setup the file system
35
-	 *
36
-	 * @param string|null $user
37
-	 * @return boolean
38
-	 * @description configure the initial filesystem based on the configuration
39
-	 * @suppress PhanDeprecatedFunction
40
-	 * @suppress PhanAccessMethodInternal
41
-	 */
42
-	public static function setupFS(?string $user = '') {
43
-		// If we are not forced to load a specific user we load the one that is logged in
44
-		if ($user === '') {
45
-			$userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
46
-		} else {
47
-			$userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
48
-		}
49
-
50
-		/** @var SetupManager $setupManager */
51
-		$setupManager = \OC::$server->get(SetupManager::class);
52
-
53
-		if ($userObject) {
54
-			$setupManager->setupForUser($userObject);
55
-		} else {
56
-			$setupManager->setupRoot();
57
-		}
58
-		return true;
59
-	}
60
-
61
-	/**
62
-	 * Check if a password is required for each public link
63
-	 *
64
-	 * @param bool $checkGroupMembership Check group membership exclusion
65
-	 * @return boolean
66
-	 * @suppress PhanDeprecatedFunction
67
-	 */
68
-	public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
69
-		/** @var IManager $shareManager */
70
-		$shareManager = \OC::$server->get(IManager::class);
71
-		return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
72
-	}
73
-
74
-	/**
75
-	 * check if sharing is disabled for the current user
76
-	 * @param IConfig $config
77
-	 * @param IGroupManager $groupManager
78
-	 * @param IUser|null $user
79
-	 * @return bool
80
-	 */
81
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
82
-		/** @var IManager $shareManager */
83
-		$shareManager = \OC::$server->get(IManager::class);
84
-		$userId = $user ? $user->getUID() : null;
85
-		return $shareManager->sharingDisabledForUser($userId);
86
-	}
87
-
88
-	/**
89
-	 * check if share API enforces a default expire date
90
-	 *
91
-	 * @return bool
92
-	 * @suppress PhanDeprecatedFunction
93
-	 */
94
-	public static function isDefaultExpireDateEnforced() {
95
-		/** @var IManager $shareManager */
96
-		$shareManager = \OC::$server->get(IManager::class);
97
-		return $shareManager->shareApiLinkDefaultExpireDateEnforced();
98
-	}
99
-
100
-	/**
101
-	 * Get the quota of a user
102
-	 *
103
-	 * @param IUser|null $user
104
-	 * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
105
-	 */
106
-	public static function getUserQuota(?IUser $user) {
107
-		if (is_null($user)) {
108
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
109
-		}
110
-		$userQuota = $user->getQuota();
111
-		if ($userQuota === 'none') {
112
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
113
-		}
114
-		return OC_Helper::computerFileSize($userQuota);
115
-	}
116
-
117
-	/**
118
-	 * copies the skeleton to the users /files
119
-	 *
120
-	 * @param string $userId
121
-	 * @param \OCP\Files\Folder $userDirectory
122
-	 * @throws \OCP\Files\NotFoundException
123
-	 * @throws \OCP\Files\NotPermittedException
124
-	 * @suppress PhanDeprecatedFunction
125
-	 */
126
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
127
-		/** @var LoggerInterface $logger */
128
-		$logger = \OC::$server->get(LoggerInterface::class);
129
-
130
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
131
-		$userLang = \OC::$server->get(IFactory::class)->findLanguage();
132
-		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
133
-
134
-		if (!file_exists($skeletonDirectory)) {
135
-			$dialectStart = strpos($userLang, '_');
136
-			if ($dialectStart !== false) {
137
-				$skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
138
-			}
139
-			if ($dialectStart === false || !file_exists($skeletonDirectory)) {
140
-				$skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
141
-			}
142
-			if (!file_exists($skeletonDirectory)) {
143
-				$skeletonDirectory = '';
144
-			}
145
-		}
146
-
147
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
148
-
149
-		if ($instanceId === null) {
150
-			throw new \RuntimeException('no instance id!');
151
-		}
152
-		$appdata = 'appdata_' . $instanceId;
153
-		if ($userId === $appdata) {
154
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
155
-		}
156
-
157
-		if (!empty($skeletonDirectory)) {
158
-			$logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
159
-			self::copyr($skeletonDirectory, $userDirectory);
160
-			// update the file cache
161
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
162
-
163
-			/** @var ITemplateManager $templateManager */
164
-			$templateManager = \OC::$server->get(ITemplateManager::class);
165
-			$templateManager->initializeTemplateDirectory(null, $userId);
166
-		}
167
-	}
168
-
169
-	/**
170
-	 * copies a directory recursively by using streams
171
-	 *
172
-	 * @param string $source
173
-	 * @param \OCP\Files\Folder $target
174
-	 * @return void
175
-	 */
176
-	public static function copyr($source, \OCP\Files\Folder $target) {
177
-		$logger = \OCP\Server::get(LoggerInterface::class);
178
-
179
-		// Verify if folder exists
180
-		$dir = opendir($source);
181
-		if ($dir === false) {
182
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
183
-			return;
184
-		}
185
-
186
-		// Copy the files
187
-		while (false !== ($file = readdir($dir))) {
188
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
189
-				if (is_dir($source . '/' . $file)) {
190
-					$child = $target->newFolder($file);
191
-					self::copyr($source . '/' . $file, $child);
192
-				} else {
193
-					$child = $target->newFile($file);
194
-					$sourceStream = fopen($source . '/' . $file, 'r');
195
-					if ($sourceStream === false) {
196
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
197
-						closedir($dir);
198
-						return;
199
-					}
200
-					$child->putContent($sourceStream);
201
-				}
202
-			}
203
-		}
204
-		closedir($dir);
205
-	}
206
-
207
-	/**
208
-	 * @return void
209
-	 * @suppress PhanUndeclaredMethod
210
-	 */
211
-	public static function tearDownFS() {
212
-		/** @var SetupManager $setupManager */
213
-		$setupManager = \OC::$server->get(SetupManager::class);
214
-		$setupManager->tearDown();
215
-	}
216
-
217
-	/**
218
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
219
-	 *
220
-	 * @param string $application application to get the files from
221
-	 * @param string $directory directory within this application (css, js, vendor, etc)
222
-	 * @param string $file the file inside of the above folder
223
-	 * @return string the path
224
-	 */
225
-	private static function generatePath($application, $directory, $file) {
226
-		if (is_null($file)) {
227
-			$file = $application;
228
-			$application = '';
229
-		}
230
-		if (!empty($application)) {
231
-			return "$application/$directory/$file";
232
-		} else {
233
-			return "$directory/$file";
234
-		}
235
-	}
236
-
237
-	/**
238
-	 * add a css file
239
-	 *
240
-	 * @param string $application application id
241
-	 * @param string|null $file filename
242
-	 * @param bool $prepend prepend the Style to the beginning of the list
243
-	 * @return void
244
-	 */
245
-	public static function addStyle($application, $file = null, $prepend = false) {
246
-		$path = OC_Util::generatePath($application, 'css', $file);
247
-		self::addExternalResource($application, $prepend, $path, 'style');
248
-	}
249
-
250
-	/**
251
-	 * add a css file from the vendor sub folder
252
-	 *
253
-	 * @param string $application application id
254
-	 * @param string|null $file filename
255
-	 * @param bool $prepend prepend the Style to the beginning of the list
256
-	 * @return void
257
-	 */
258
-	public static function addVendorStyle($application, $file = null, $prepend = false) {
259
-		$path = OC_Util::generatePath($application, 'vendor', $file);
260
-		self::addExternalResource($application, $prepend, $path, 'style');
261
-	}
262
-
263
-	/**
264
-	 * add an external resource css/js file
265
-	 *
266
-	 * @param string $application application id
267
-	 * @param bool $prepend prepend the file to the beginning of the list
268
-	 * @param string $path
269
-	 * @param string $type (script or style)
270
-	 * @return void
271
-	 */
272
-	private static function addExternalResource($application, $prepend, $path, $type = 'script') {
273
-		if ($type === 'style') {
274
-			if (!in_array($path, self::$styles)) {
275
-				if ($prepend === true) {
276
-					array_unshift(self::$styles, $path);
277
-				} else {
278
-					self::$styles[] = $path;
279
-				}
280
-			}
281
-		}
282
-	}
283
-
284
-	/**
285
-	 * Add a custom element to the header
286
-	 * If $text is null then the element will be written as empty element.
287
-	 * So use "" to get a closing tag.
288
-	 * @param string $tag tag name of the element
289
-	 * @param array $attributes array of attributes for the element
290
-	 * @param string $text the text content for the element
291
-	 * @param bool $prepend prepend the header to the beginning of the list
292
-	 */
293
-	public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
294
-		$header = [
295
-			'tag' => $tag,
296
-			'attributes' => $attributes,
297
-			'text' => $text
298
-		];
299
-		if ($prepend === true) {
300
-			array_unshift(self::$headers, $header);
301
-		} else {
302
-			self::$headers[] = $header;
303
-		}
304
-	}
305
-
306
-	/**
307
-	 * check if the current server configuration is suitable for ownCloud
308
-	 *
309
-	 * @param \OC\SystemConfig $config
310
-	 * @return array arrays with error messages and hints
311
-	 */
312
-	public static function checkServer(\OC\SystemConfig $config) {
313
-		$l = \OC::$server->getL10N('lib');
314
-		$errors = [];
315
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
316
-
317
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
318
-			// this check needs to be done every time
319
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
320
-		}
321
-
322
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
323
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
324
-			return $errors;
325
-		}
326
-
327
-		$webServerRestart = false;
328
-		$setup = \OCP\Server::get(\OC\Setup::class);
329
-
330
-		$urlGenerator = \OC::$server->getURLGenerator();
331
-
332
-		$availableDatabases = $setup->getSupportedDatabases();
333
-		if (empty($availableDatabases)) {
334
-			$errors[] = [
335
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
336
-				'hint' => '' //TODO: sane hint
337
-			];
338
-			$webServerRestart = true;
339
-		}
340
-
341
-		// Check if config folder is writable.
342
-		if (!OC_Helper::isReadOnlyConfigEnabled()) {
343
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
344
-				$errors[] = [
345
-					'error' => $l->t('Cannot write into "config" directory.'),
346
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
347
-						[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
348
-						. $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
349
-							[ $urlGenerator->linkToDocs('admin-config') ])
350
-				];
351
-			}
352
-		}
353
-
354
-		// Check if there is a writable install folder.
355
-		if ($config->getValue('appstoreenabled', true)) {
356
-			if (OC_App::getInstallPath() === null
357
-				|| !is_writable(OC_App::getInstallPath())
358
-				|| !is_readable(OC_App::getInstallPath())
359
-			) {
360
-				$errors[] = [
361
-					'error' => $l->t('Cannot write into "apps" directory.'),
362
-					'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
363
-						. ' or disabling the App Store in the config file.')
364
-				];
365
-			}
366
-		}
367
-		// Create root dir.
368
-		if ($config->getValue('installed', false)) {
369
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
370
-				$success = @mkdir($CONFIG_DATADIRECTORY);
371
-				if ($success) {
372
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
373
-				} else {
374
-					$errors[] = [
375
-						'error' => $l->t('Cannot create "data" directory.'),
376
-						'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
377
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
378
-					];
379
-				}
380
-			} elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
381
-				// is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
382
-				$testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
383
-				$handle = fopen($testFile, 'w');
384
-				if (!$handle || fwrite($handle, 'Test write operation') === false) {
385
-					$permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
386
-						[$urlGenerator->linkToDocs('admin-dir_permissions')]);
387
-					$errors[] = [
388
-						'error' => $l->t('Your data directory is not writable.'),
389
-						'hint' => $permissionsHint
390
-					];
391
-				} else {
392
-					fclose($handle);
393
-					unlink($testFile);
394
-				}
395
-			} else {
396
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
397
-			}
398
-		}
399
-
400
-		if (!OC_Util::isSetLocaleWorking()) {
401
-			$errors[] = [
402
-				'error' => $l->t('Setting locale to %s failed.',
403
-					['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
404
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
405
-				'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
406
-			];
407
-		}
408
-
409
-		// Contains the dependencies that should be checked against
410
-		// classes = class_exists
411
-		// functions = function_exists
412
-		// defined = defined
413
-		// ini = ini_get
414
-		// If the dependency is not found the missing module name is shown to the EndUser
415
-		// When adding new checks always verify that they pass on CI as well
416
-		$dependencies = [
417
-			'classes' => [
418
-				'ZipArchive' => 'zip',
419
-				'DOMDocument' => 'dom',
420
-				'XMLWriter' => 'XMLWriter',
421
-				'XMLReader' => 'XMLReader',
422
-			],
423
-			'functions' => [
424
-				'xml_parser_create' => 'libxml',
425
-				'mb_strcut' => 'mbstring',
426
-				'ctype_digit' => 'ctype',
427
-				'json_encode' => 'JSON',
428
-				'gd_info' => 'GD',
429
-				'gzencode' => 'zlib',
430
-				'simplexml_load_string' => 'SimpleXML',
431
-				'hash' => 'HASH Message Digest Framework',
432
-				'curl_init' => 'cURL',
433
-				'openssl_verify' => 'OpenSSL',
434
-			],
435
-			'defined' => [
436
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
437
-			],
438
-			'ini' => [
439
-				'default_charset' => 'UTF-8',
440
-			],
441
-		];
442
-		$missingDependencies = [];
443
-		$invalidIniSettings = [];
444
-
445
-		$iniWrapper = \OC::$server->get(IniGetWrapper::class);
446
-		foreach ($dependencies['classes'] as $class => $module) {
447
-			if (!class_exists($class)) {
448
-				$missingDependencies[] = $module;
449
-			}
450
-		}
451
-		foreach ($dependencies['functions'] as $function => $module) {
452
-			if (!function_exists($function)) {
453
-				$missingDependencies[] = $module;
454
-			}
455
-		}
456
-		foreach ($dependencies['defined'] as $defined => $module) {
457
-			if (!defined($defined)) {
458
-				$missingDependencies[] = $module;
459
-			}
460
-		}
461
-		foreach ($dependencies['ini'] as $setting => $expected) {
462
-			if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
463
-				$invalidIniSettings[] = [$setting, $expected];
464
-			}
465
-		}
466
-
467
-		foreach ($missingDependencies as $missingDependency) {
468
-			$errors[] = [
469
-				'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
470
-				'hint' => $l->t('Please ask your server administrator to install the module.'),
471
-			];
472
-			$webServerRestart = true;
473
-		}
474
-		foreach ($invalidIniSettings as $setting) {
475
-			$errors[] = [
476
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
477
-				'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
478
-			];
479
-			$webServerRestart = true;
480
-		}
481
-
482
-		/**
483
-		 * The mbstring.func_overload check can only be performed if the mbstring
484
-		 * module is installed as it will return null if the checking setting is
485
-		 * not available and thus a check on the boolean value fails.
486
-		 *
487
-		 * TODO: Should probably be implemented in the above generic dependency
488
-		 *       check somehow in the long-term.
489
-		 */
490
-		if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
491
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
492
-			$errors[] = [
493
-				'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]),
494
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
495
-			];
496
-		}
497
-
498
-		if (!self::isAnnotationsWorking()) {
499
-			$errors[] = [
500
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
501
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
502
-			];
503
-		}
504
-
505
-		if (!\OC::$CLI && $webServerRestart) {
506
-			$errors[] = [
507
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
508
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
509
-			];
510
-		}
511
-
512
-		foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
513
-			if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
514
-				$errors[] = [
515
-					'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
516
-					'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
517
-				];
518
-			}
519
-		}
520
-
521
-		// Cache the result of this function
522
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
523
-
524
-		return $errors;
525
-	}
526
-
527
-	/**
528
-	 * Check for correct file permissions of data directory
529
-	 *
530
-	 * @param string $dataDirectory
531
-	 * @return array arrays with error messages and hints
532
-	 */
533
-	public static function checkDataDirectoryPermissions($dataDirectory) {
534
-		if (!\OC::$server->getConfig()->getSystemValueBool('check_data_directory_permissions', true)) {
535
-			return  [];
536
-		}
537
-
538
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
539
-		if (substr($perms, -1) !== '0') {
540
-			chmod($dataDirectory, 0770);
541
-			clearstatcache();
542
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
543
-			if ($perms[2] !== '0') {
544
-				$l = \OC::$server->getL10N('lib');
545
-				return [[
546
-					'error' => $l->t('Your data directory is readable by other people.'),
547
-					'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'),
548
-				]];
549
-			}
550
-		}
551
-		return [];
552
-	}
553
-
554
-	/**
555
-	 * Check that the data directory exists and is valid by
556
-	 * checking the existence of the ".ncdata" file.
557
-	 *
558
-	 * @param string $dataDirectory data directory path
559
-	 * @return array errors found
560
-	 */
561
-	public static function checkDataDirectoryValidity($dataDirectory) {
562
-		$l = \OC::$server->getL10N('lib');
563
-		$errors = [];
564
-		if ($dataDirectory[0] !== '/') {
565
-			$errors[] = [
566
-				'error' => $l->t('Your data directory must be an absolute path.'),
567
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
568
-			];
569
-		}
570
-
571
-		if (!file_exists($dataDirectory . '/.ncdata')) {
572
-			$errors[] = [
573
-				'error' => $l->t('Your data directory is invalid.'),
574
-				'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
575
-			];
576
-		}
577
-		return $errors;
578
-	}
579
-
580
-	/**
581
-	 * Check if the user is logged in, redirects to home if not. With
582
-	 * redirect URL parameter to the request URI.
583
-	 *
584
-	 * @return void
585
-	 */
586
-	public static function checkLoggedIn() {
587
-		// Check if we are a user
588
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
589
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
590
-				'core.login.showLoginForm',
591
-				[
592
-					'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
593
-				]
594
-			)
595
-			);
596
-			exit();
597
-		}
598
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
599
-		if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
600
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
601
-			exit();
602
-		}
603
-	}
604
-
605
-	/**
606
-	 * Check if the user is a admin, redirects to home if not
607
-	 *
608
-	 * @return void
609
-	 */
610
-	public static function checkAdminUser() {
611
-		OC_Util::checkLoggedIn();
612
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
613
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
614
-			exit();
615
-		}
616
-	}
617
-
618
-	/**
619
-	 * Returns the URL of the default page
620
-	 * based on the system configuration and
621
-	 * the apps visible for the current user
622
-	 *
623
-	 * @return string URL
624
-	 * @suppress PhanDeprecatedFunction
625
-	 */
626
-	public static function getDefaultPageUrl() {
627
-		/** @var IURLGenerator $urlGenerator */
628
-		$urlGenerator = \OC::$server->get(IURLGenerator::class);
629
-		return $urlGenerator->linkToDefaultPageUrl();
630
-	}
631
-
632
-	/**
633
-	 * Redirect to the user default page
634
-	 *
635
-	 * @return void
636
-	 */
637
-	public static function redirectToDefaultPage() {
638
-		$location = self::getDefaultPageUrl();
639
-		header('Location: ' . $location);
640
-		exit();
641
-	}
642
-
643
-	/**
644
-	 * get an id unique for this instance
645
-	 *
646
-	 * @return string
647
-	 */
648
-	public static function getInstanceId() {
649
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
650
-		if (is_null($id)) {
651
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
652
-			$id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
653
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
654
-		}
655
-		return $id;
656
-	}
657
-
658
-	/**
659
-	 * Public function to sanitize HTML
660
-	 *
661
-	 * This function is used to sanitize HTML and should be applied on any
662
-	 * string or array of strings before displaying it on a web page.
663
-	 *
664
-	 * @param string|string[] $value
665
-	 * @return ($value is array ? string[] : string)
666
-	 */
667
-	public static function sanitizeHTML($value) {
668
-		if (is_array($value)) {
669
-			$value = array_map(function ($value) {
670
-				return self::sanitizeHTML($value);
671
-			}, $value);
672
-		} else {
673
-			// Specify encoding for PHP<5.4
674
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
675
-		}
676
-		return $value;
677
-	}
678
-
679
-	/**
680
-	 * Public function to encode url parameters
681
-	 *
682
-	 * This function is used to encode path to file before output.
683
-	 * Encoding is done according to RFC 3986 with one exception:
684
-	 * Character '/' is preserved as is.
685
-	 *
686
-	 * @param string $component part of URI to encode
687
-	 * @return string
688
-	 */
689
-	public static function encodePath($component) {
690
-		$encoded = rawurlencode($component);
691
-		$encoded = str_replace('%2F', '/', $encoded);
692
-		return $encoded;
693
-	}
694
-
695
-
696
-	public function createHtaccessTestFile(\OCP\IConfig $config) {
697
-		// php dev server does not support htaccess
698
-		if (php_sapi_name() === 'cli-server') {
699
-			return false;
700
-		}
701
-
702
-		// testdata
703
-		$fileName = '/htaccesstest.txt';
704
-		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
705
-
706
-		// creating a test file
707
-		$testFile = $config->getSystemValueString('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
708
-
709
-		if (file_exists($testFile)) {// already running this test, possible recursive call
710
-			return false;
711
-		}
712
-
713
-		$fp = @fopen($testFile, 'w');
714
-		if (!$fp) {
715
-			throw new \OCP\HintException('Can\'t create test file to check for working .htaccess file.',
716
-				'Make sure it is possible for the web server to write to ' . $testFile);
717
-		}
718
-		fwrite($fp, $testContent);
719
-		fclose($fp);
720
-
721
-		return $testContent;
722
-	}
723
-
724
-	/**
725
-	 * Check if the .htaccess file is working
726
-	 *
727
-	 * @param \OCP\IConfig $config
728
-	 * @return bool
729
-	 * @throws Exception
730
-	 * @throws \OCP\HintException If the test file can't get written.
731
-	 */
732
-	public function isHtaccessWorking(\OCP\IConfig $config) {
733
-		if (\OC::$CLI || !$config->getSystemValueBool('check_for_working_htaccess', true)) {
734
-			return true;
735
-		}
736
-
737
-		$testContent = $this->createHtaccessTestFile($config);
738
-		if ($testContent === false) {
739
-			return false;
740
-		}
741
-
742
-		$fileName = '/htaccesstest.txt';
743
-		$testFile = $config->getSystemValueString('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
744
-
745
-		// accessing the file via http
746
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
747
-		try {
748
-			$content = \OC::$server->get(IClientService::class)->newClient()->get($url)->getBody();
749
-		} catch (\Exception $e) {
750
-			$content = false;
751
-		}
752
-
753
-		if (str_starts_with($url, 'https:')) {
754
-			$url = 'http:' . substr($url, 6);
755
-		} else {
756
-			$url = 'https:' . substr($url, 5);
757
-		}
758
-
759
-		try {
760
-			$fallbackContent = \OC::$server->get(IClientService::class)->newClient()->get($url)->getBody();
761
-		} catch (\Exception $e) {
762
-			$fallbackContent = false;
763
-		}
764
-
765
-		// cleanup
766
-		@unlink($testFile);
767
-
768
-		/*
23
+    public static $styles = [];
24
+    public static $headers = [];
25
+
26
+    /** @var array Local cache of version.php */
27
+    private static $versionCache = null;
28
+
29
+    protected static function getAppManager() {
30
+        return \OC::$server->getAppManager();
31
+    }
32
+
33
+    /**
34
+     * Setup the file system
35
+     *
36
+     * @param string|null $user
37
+     * @return boolean
38
+     * @description configure the initial filesystem based on the configuration
39
+     * @suppress PhanDeprecatedFunction
40
+     * @suppress PhanAccessMethodInternal
41
+     */
42
+    public static function setupFS(?string $user = '') {
43
+        // If we are not forced to load a specific user we load the one that is logged in
44
+        if ($user === '') {
45
+            $userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser();
46
+        } else {
47
+            $userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user);
48
+        }
49
+
50
+        /** @var SetupManager $setupManager */
51
+        $setupManager = \OC::$server->get(SetupManager::class);
52
+
53
+        if ($userObject) {
54
+            $setupManager->setupForUser($userObject);
55
+        } else {
56
+            $setupManager->setupRoot();
57
+        }
58
+        return true;
59
+    }
60
+
61
+    /**
62
+     * Check if a password is required for each public link
63
+     *
64
+     * @param bool $checkGroupMembership Check group membership exclusion
65
+     * @return boolean
66
+     * @suppress PhanDeprecatedFunction
67
+     */
68
+    public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) {
69
+        /** @var IManager $shareManager */
70
+        $shareManager = \OC::$server->get(IManager::class);
71
+        return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership);
72
+    }
73
+
74
+    /**
75
+     * check if sharing is disabled for the current user
76
+     * @param IConfig $config
77
+     * @param IGroupManager $groupManager
78
+     * @param IUser|null $user
79
+     * @return bool
80
+     */
81
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
82
+        /** @var IManager $shareManager */
83
+        $shareManager = \OC::$server->get(IManager::class);
84
+        $userId = $user ? $user->getUID() : null;
85
+        return $shareManager->sharingDisabledForUser($userId);
86
+    }
87
+
88
+    /**
89
+     * check if share API enforces a default expire date
90
+     *
91
+     * @return bool
92
+     * @suppress PhanDeprecatedFunction
93
+     */
94
+    public static function isDefaultExpireDateEnforced() {
95
+        /** @var IManager $shareManager */
96
+        $shareManager = \OC::$server->get(IManager::class);
97
+        return $shareManager->shareApiLinkDefaultExpireDateEnforced();
98
+    }
99
+
100
+    /**
101
+     * Get the quota of a user
102
+     *
103
+     * @param IUser|null $user
104
+     * @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
105
+     */
106
+    public static function getUserQuota(?IUser $user) {
107
+        if (is_null($user)) {
108
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
109
+        }
110
+        $userQuota = $user->getQuota();
111
+        if ($userQuota === 'none') {
112
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
113
+        }
114
+        return OC_Helper::computerFileSize($userQuota);
115
+    }
116
+
117
+    /**
118
+     * copies the skeleton to the users /files
119
+     *
120
+     * @param string $userId
121
+     * @param \OCP\Files\Folder $userDirectory
122
+     * @throws \OCP\Files\NotFoundException
123
+     * @throws \OCP\Files\NotPermittedException
124
+     * @suppress PhanDeprecatedFunction
125
+     */
126
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
127
+        /** @var LoggerInterface $logger */
128
+        $logger = \OC::$server->get(LoggerInterface::class);
129
+
130
+        $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValueString('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
131
+        $userLang = \OC::$server->get(IFactory::class)->findLanguage();
132
+        $skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
133
+
134
+        if (!file_exists($skeletonDirectory)) {
135
+            $dialectStart = strpos($userLang, '_');
136
+            if ($dialectStart !== false) {
137
+                $skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
138
+            }
139
+            if ($dialectStart === false || !file_exists($skeletonDirectory)) {
140
+                $skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
141
+            }
142
+            if (!file_exists($skeletonDirectory)) {
143
+                $skeletonDirectory = '';
144
+            }
145
+        }
146
+
147
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
148
+
149
+        if ($instanceId === null) {
150
+            throw new \RuntimeException('no instance id!');
151
+        }
152
+        $appdata = 'appdata_' . $instanceId;
153
+        if ($userId === $appdata) {
154
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
155
+        }
156
+
157
+        if (!empty($skeletonDirectory)) {
158
+            $logger->debug('copying skeleton for ' . $userId . ' from ' . $skeletonDirectory . ' to ' . $userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
159
+            self::copyr($skeletonDirectory, $userDirectory);
160
+            // update the file cache
161
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
162
+
163
+            /** @var ITemplateManager $templateManager */
164
+            $templateManager = \OC::$server->get(ITemplateManager::class);
165
+            $templateManager->initializeTemplateDirectory(null, $userId);
166
+        }
167
+    }
168
+
169
+    /**
170
+     * copies a directory recursively by using streams
171
+     *
172
+     * @param string $source
173
+     * @param \OCP\Files\Folder $target
174
+     * @return void
175
+     */
176
+    public static function copyr($source, \OCP\Files\Folder $target) {
177
+        $logger = \OCP\Server::get(LoggerInterface::class);
178
+
179
+        // Verify if folder exists
180
+        $dir = opendir($source);
181
+        if ($dir === false) {
182
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
183
+            return;
184
+        }
185
+
186
+        // Copy the files
187
+        while (false !== ($file = readdir($dir))) {
188
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
189
+                if (is_dir($source . '/' . $file)) {
190
+                    $child = $target->newFolder($file);
191
+                    self::copyr($source . '/' . $file, $child);
192
+                } else {
193
+                    $child = $target->newFile($file);
194
+                    $sourceStream = fopen($source . '/' . $file, 'r');
195
+                    if ($sourceStream === false) {
196
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
197
+                        closedir($dir);
198
+                        return;
199
+                    }
200
+                    $child->putContent($sourceStream);
201
+                }
202
+            }
203
+        }
204
+        closedir($dir);
205
+    }
206
+
207
+    /**
208
+     * @return void
209
+     * @suppress PhanUndeclaredMethod
210
+     */
211
+    public static function tearDownFS() {
212
+        /** @var SetupManager $setupManager */
213
+        $setupManager = \OC::$server->get(SetupManager::class);
214
+        $setupManager->tearDown();
215
+    }
216
+
217
+    /**
218
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
219
+     *
220
+     * @param string $application application to get the files from
221
+     * @param string $directory directory within this application (css, js, vendor, etc)
222
+     * @param string $file the file inside of the above folder
223
+     * @return string the path
224
+     */
225
+    private static function generatePath($application, $directory, $file) {
226
+        if (is_null($file)) {
227
+            $file = $application;
228
+            $application = '';
229
+        }
230
+        if (!empty($application)) {
231
+            return "$application/$directory/$file";
232
+        } else {
233
+            return "$directory/$file";
234
+        }
235
+    }
236
+
237
+    /**
238
+     * add a css file
239
+     *
240
+     * @param string $application application id
241
+     * @param string|null $file filename
242
+     * @param bool $prepend prepend the Style to the beginning of the list
243
+     * @return void
244
+     */
245
+    public static function addStyle($application, $file = null, $prepend = false) {
246
+        $path = OC_Util::generatePath($application, 'css', $file);
247
+        self::addExternalResource($application, $prepend, $path, 'style');
248
+    }
249
+
250
+    /**
251
+     * add a css file from the vendor sub folder
252
+     *
253
+     * @param string $application application id
254
+     * @param string|null $file filename
255
+     * @param bool $prepend prepend the Style to the beginning of the list
256
+     * @return void
257
+     */
258
+    public static function addVendorStyle($application, $file = null, $prepend = false) {
259
+        $path = OC_Util::generatePath($application, 'vendor', $file);
260
+        self::addExternalResource($application, $prepend, $path, 'style');
261
+    }
262
+
263
+    /**
264
+     * add an external resource css/js file
265
+     *
266
+     * @param string $application application id
267
+     * @param bool $prepend prepend the file to the beginning of the list
268
+     * @param string $path
269
+     * @param string $type (script or style)
270
+     * @return void
271
+     */
272
+    private static function addExternalResource($application, $prepend, $path, $type = 'script') {
273
+        if ($type === 'style') {
274
+            if (!in_array($path, self::$styles)) {
275
+                if ($prepend === true) {
276
+                    array_unshift(self::$styles, $path);
277
+                } else {
278
+                    self::$styles[] = $path;
279
+                }
280
+            }
281
+        }
282
+    }
283
+
284
+    /**
285
+     * Add a custom element to the header
286
+     * If $text is null then the element will be written as empty element.
287
+     * So use "" to get a closing tag.
288
+     * @param string $tag tag name of the element
289
+     * @param array $attributes array of attributes for the element
290
+     * @param string $text the text content for the element
291
+     * @param bool $prepend prepend the header to the beginning of the list
292
+     */
293
+    public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
294
+        $header = [
295
+            'tag' => $tag,
296
+            'attributes' => $attributes,
297
+            'text' => $text
298
+        ];
299
+        if ($prepend === true) {
300
+            array_unshift(self::$headers, $header);
301
+        } else {
302
+            self::$headers[] = $header;
303
+        }
304
+    }
305
+
306
+    /**
307
+     * check if the current server configuration is suitable for ownCloud
308
+     *
309
+     * @param \OC\SystemConfig $config
310
+     * @return array arrays with error messages and hints
311
+     */
312
+    public static function checkServer(\OC\SystemConfig $config) {
313
+        $l = \OC::$server->getL10N('lib');
314
+        $errors = [];
315
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
316
+
317
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
318
+            // this check needs to be done every time
319
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
320
+        }
321
+
322
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
323
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
324
+            return $errors;
325
+        }
326
+
327
+        $webServerRestart = false;
328
+        $setup = \OCP\Server::get(\OC\Setup::class);
329
+
330
+        $urlGenerator = \OC::$server->getURLGenerator();
331
+
332
+        $availableDatabases = $setup->getSupportedDatabases();
333
+        if (empty($availableDatabases)) {
334
+            $errors[] = [
335
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
336
+                'hint' => '' //TODO: sane hint
337
+            ];
338
+            $webServerRestart = true;
339
+        }
340
+
341
+        // Check if config folder is writable.
342
+        if (!OC_Helper::isReadOnlyConfigEnabled()) {
343
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
344
+                $errors[] = [
345
+                    'error' => $l->t('Cannot write into "config" directory.'),
346
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the config directory. See %s',
347
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
348
+                        . $l->t('Or, if you prefer to keep config.php file read only, set the option "config_is_read_only" to true in it. See %s',
349
+                            [ $urlGenerator->linkToDocs('admin-config') ])
350
+                ];
351
+            }
352
+        }
353
+
354
+        // Check if there is a writable install folder.
355
+        if ($config->getValue('appstoreenabled', true)) {
356
+            if (OC_App::getInstallPath() === null
357
+                || !is_writable(OC_App::getInstallPath())
358
+                || !is_readable(OC_App::getInstallPath())
359
+            ) {
360
+                $errors[] = [
361
+                    'error' => $l->t('Cannot write into "apps" directory.'),
362
+                    'hint' => $l->t('This can usually be fixed by giving the web server write access to the apps directory'
363
+                        . ' or disabling the App Store in the config file.')
364
+                ];
365
+            }
366
+        }
367
+        // Create root dir.
368
+        if ($config->getValue('installed', false)) {
369
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
370
+                $success = @mkdir($CONFIG_DATADIRECTORY);
371
+                if ($success) {
372
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
373
+                } else {
374
+                    $errors[] = [
375
+                        'error' => $l->t('Cannot create "data" directory.'),
376
+                        'hint' => $l->t('This can usually be fixed by giving the web server write access to the root directory. See %s',
377
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
378
+                    ];
379
+                }
380
+            } elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
381
+                // is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
382
+                $testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
383
+                $handle = fopen($testFile, 'w');
384
+                if (!$handle || fwrite($handle, 'Test write operation') === false) {
385
+                    $permissionsHint = $l->t('Permissions can usually be fixed by giving the web server write access to the root directory. See %s.',
386
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')]);
387
+                    $errors[] = [
388
+                        'error' => $l->t('Your data directory is not writable.'),
389
+                        'hint' => $permissionsHint
390
+                    ];
391
+                } else {
392
+                    fclose($handle);
393
+                    unlink($testFile);
394
+                }
395
+            } else {
396
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
397
+            }
398
+        }
399
+
400
+        if (!OC_Util::isSetLocaleWorking()) {
401
+            $errors[] = [
402
+                'error' => $l->t('Setting locale to %s failed.',
403
+                    ['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
404
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
405
+                'hint' => $l->t('Please install one of these locales on your system and restart your web server.')
406
+            ];
407
+        }
408
+
409
+        // Contains the dependencies that should be checked against
410
+        // classes = class_exists
411
+        // functions = function_exists
412
+        // defined = defined
413
+        // ini = ini_get
414
+        // If the dependency is not found the missing module name is shown to the EndUser
415
+        // When adding new checks always verify that they pass on CI as well
416
+        $dependencies = [
417
+            'classes' => [
418
+                'ZipArchive' => 'zip',
419
+                'DOMDocument' => 'dom',
420
+                'XMLWriter' => 'XMLWriter',
421
+                'XMLReader' => 'XMLReader',
422
+            ],
423
+            'functions' => [
424
+                'xml_parser_create' => 'libxml',
425
+                'mb_strcut' => 'mbstring',
426
+                'ctype_digit' => 'ctype',
427
+                'json_encode' => 'JSON',
428
+                'gd_info' => 'GD',
429
+                'gzencode' => 'zlib',
430
+                'simplexml_load_string' => 'SimpleXML',
431
+                'hash' => 'HASH Message Digest Framework',
432
+                'curl_init' => 'cURL',
433
+                'openssl_verify' => 'OpenSSL',
434
+            ],
435
+            'defined' => [
436
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
437
+            ],
438
+            'ini' => [
439
+                'default_charset' => 'UTF-8',
440
+            ],
441
+        ];
442
+        $missingDependencies = [];
443
+        $invalidIniSettings = [];
444
+
445
+        $iniWrapper = \OC::$server->get(IniGetWrapper::class);
446
+        foreach ($dependencies['classes'] as $class => $module) {
447
+            if (!class_exists($class)) {
448
+                $missingDependencies[] = $module;
449
+            }
450
+        }
451
+        foreach ($dependencies['functions'] as $function => $module) {
452
+            if (!function_exists($function)) {
453
+                $missingDependencies[] = $module;
454
+            }
455
+        }
456
+        foreach ($dependencies['defined'] as $defined => $module) {
457
+            if (!defined($defined)) {
458
+                $missingDependencies[] = $module;
459
+            }
460
+        }
461
+        foreach ($dependencies['ini'] as $setting => $expected) {
462
+            if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
463
+                $invalidIniSettings[] = [$setting, $expected];
464
+            }
465
+        }
466
+
467
+        foreach ($missingDependencies as $missingDependency) {
468
+            $errors[] = [
469
+                'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
470
+                'hint' => $l->t('Please ask your server administrator to install the module.'),
471
+            ];
472
+            $webServerRestart = true;
473
+        }
474
+        foreach ($invalidIniSettings as $setting) {
475
+            $errors[] = [
476
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
477
+                'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
478
+            ];
479
+            $webServerRestart = true;
480
+        }
481
+
482
+        /**
483
+         * The mbstring.func_overload check can only be performed if the mbstring
484
+         * module is installed as it will return null if the checking setting is
485
+         * not available and thus a check on the boolean value fails.
486
+         *
487
+         * TODO: Should probably be implemented in the above generic dependency
488
+         *       check somehow in the long-term.
489
+         */
490
+        if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
491
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
492
+            $errors[] = [
493
+                'error' => $l->t('<code>mbstring.func_overload</code> is set to <code>%s</code> instead of the expected value <code>0</code>.', [$iniWrapper->getString('mbstring.func_overload')]),
494
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini.')
495
+            ];
496
+        }
497
+
498
+        if (!self::isAnnotationsWorking()) {
499
+            $errors[] = [
500
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
501
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
502
+            ];
503
+        }
504
+
505
+        if (!\OC::$CLI && $webServerRestart) {
506
+            $errors[] = [
507
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
508
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
509
+            ];
510
+        }
511
+
512
+        foreach (['secret', 'instanceid', 'passwordsalt'] as $requiredConfig) {
513
+            if ($config->getValue($requiredConfig, '') === '' && !\OC::$CLI && $config->getValue('installed', false)) {
514
+                $errors[] = [
515
+                    'error' => $l->t('The required %s config variable is not configured in the config.php file.', [$requiredConfig]),
516
+                    'hint' => $l->t('Please ask your server administrator to check the Nextcloud configuration.')
517
+                ];
518
+            }
519
+        }
520
+
521
+        // Cache the result of this function
522
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
523
+
524
+        return $errors;
525
+    }
526
+
527
+    /**
528
+     * Check for correct file permissions of data directory
529
+     *
530
+     * @param string $dataDirectory
531
+     * @return array arrays with error messages and hints
532
+     */
533
+    public static function checkDataDirectoryPermissions($dataDirectory) {
534
+        if (!\OC::$server->getConfig()->getSystemValueBool('check_data_directory_permissions', true)) {
535
+            return  [];
536
+        }
537
+
538
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
539
+        if (substr($perms, -1) !== '0') {
540
+            chmod($dataDirectory, 0770);
541
+            clearstatcache();
542
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
543
+            if ($perms[2] !== '0') {
544
+                $l = \OC::$server->getL10N('lib');
545
+                return [[
546
+                    'error' => $l->t('Your data directory is readable by other people.'),
547
+                    'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other people.'),
548
+                ]];
549
+            }
550
+        }
551
+        return [];
552
+    }
553
+
554
+    /**
555
+     * Check that the data directory exists and is valid by
556
+     * checking the existence of the ".ncdata" file.
557
+     *
558
+     * @param string $dataDirectory data directory path
559
+     * @return array errors found
560
+     */
561
+    public static function checkDataDirectoryValidity($dataDirectory) {
562
+        $l = \OC::$server->getL10N('lib');
563
+        $errors = [];
564
+        if ($dataDirectory[0] !== '/') {
565
+            $errors[] = [
566
+                'error' => $l->t('Your data directory must be an absolute path.'),
567
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration.')
568
+            ];
569
+        }
570
+
571
+        if (!file_exists($dataDirectory . '/.ncdata')) {
572
+            $errors[] = [
573
+                'error' => $l->t('Your data directory is invalid.'),
574
+                'hint' => $l->t('Ensure there is a file called "%1$s" in the root of the data directory. It should have the content: "%2$s"', ['.ncdata', '# Nextcloud data directory']),
575
+            ];
576
+        }
577
+        return $errors;
578
+    }
579
+
580
+    /**
581
+     * Check if the user is logged in, redirects to home if not. With
582
+     * redirect URL parameter to the request URI.
583
+     *
584
+     * @return void
585
+     */
586
+    public static function checkLoggedIn() {
587
+        // Check if we are a user
588
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
589
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
590
+                'core.login.showLoginForm',
591
+                [
592
+                    'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
593
+                ]
594
+            )
595
+            );
596
+            exit();
597
+        }
598
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
599
+        if (\OC::$server->get(TwoFactorAuthManager::class)->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
600
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
601
+            exit();
602
+        }
603
+    }
604
+
605
+    /**
606
+     * Check if the user is a admin, redirects to home if not
607
+     *
608
+     * @return void
609
+     */
610
+    public static function checkAdminUser() {
611
+        OC_Util::checkLoggedIn();
612
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
613
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
614
+            exit();
615
+        }
616
+    }
617
+
618
+    /**
619
+     * Returns the URL of the default page
620
+     * based on the system configuration and
621
+     * the apps visible for the current user
622
+     *
623
+     * @return string URL
624
+     * @suppress PhanDeprecatedFunction
625
+     */
626
+    public static function getDefaultPageUrl() {
627
+        /** @var IURLGenerator $urlGenerator */
628
+        $urlGenerator = \OC::$server->get(IURLGenerator::class);
629
+        return $urlGenerator->linkToDefaultPageUrl();
630
+    }
631
+
632
+    /**
633
+     * Redirect to the user default page
634
+     *
635
+     * @return void
636
+     */
637
+    public static function redirectToDefaultPage() {
638
+        $location = self::getDefaultPageUrl();
639
+        header('Location: ' . $location);
640
+        exit();
641
+    }
642
+
643
+    /**
644
+     * get an id unique for this instance
645
+     *
646
+     * @return string
647
+     */
648
+    public static function getInstanceId() {
649
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
650
+        if (is_null($id)) {
651
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
652
+            $id = 'oc' . \OC::$server->get(ISecureRandom::class)->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_DIGITS);
653
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
654
+        }
655
+        return $id;
656
+    }
657
+
658
+    /**
659
+     * Public function to sanitize HTML
660
+     *
661
+     * This function is used to sanitize HTML and should be applied on any
662
+     * string or array of strings before displaying it on a web page.
663
+     *
664
+     * @param string|string[] $value
665
+     * @return ($value is array ? string[] : string)
666
+     */
667
+    public static function sanitizeHTML($value) {
668
+        if (is_array($value)) {
669
+            $value = array_map(function ($value) {
670
+                return self::sanitizeHTML($value);
671
+            }, $value);
672
+        } else {
673
+            // Specify encoding for PHP<5.4
674
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
675
+        }
676
+        return $value;
677
+    }
678
+
679
+    /**
680
+     * Public function to encode url parameters
681
+     *
682
+     * This function is used to encode path to file before output.
683
+     * Encoding is done according to RFC 3986 with one exception:
684
+     * Character '/' is preserved as is.
685
+     *
686
+     * @param string $component part of URI to encode
687
+     * @return string
688
+     */
689
+    public static function encodePath($component) {
690
+        $encoded = rawurlencode($component);
691
+        $encoded = str_replace('%2F', '/', $encoded);
692
+        return $encoded;
693
+    }
694
+
695
+
696
+    public function createHtaccessTestFile(\OCP\IConfig $config) {
697
+        // php dev server does not support htaccess
698
+        if (php_sapi_name() === 'cli-server') {
699
+            return false;
700
+        }
701
+
702
+        // testdata
703
+        $fileName = '/htaccesstest.txt';
704
+        $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
705
+
706
+        // creating a test file
707
+        $testFile = $config->getSystemValueString('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
708
+
709
+        if (file_exists($testFile)) {// already running this test, possible recursive call
710
+            return false;
711
+        }
712
+
713
+        $fp = @fopen($testFile, 'w');
714
+        if (!$fp) {
715
+            throw new \OCP\HintException('Can\'t create test file to check for working .htaccess file.',
716
+                'Make sure it is possible for the web server to write to ' . $testFile);
717
+        }
718
+        fwrite($fp, $testContent);
719
+        fclose($fp);
720
+
721
+        return $testContent;
722
+    }
723
+
724
+    /**
725
+     * Check if the .htaccess file is working
726
+     *
727
+     * @param \OCP\IConfig $config
728
+     * @return bool
729
+     * @throws Exception
730
+     * @throws \OCP\HintException If the test file can't get written.
731
+     */
732
+    public function isHtaccessWorking(\OCP\IConfig $config) {
733
+        if (\OC::$CLI || !$config->getSystemValueBool('check_for_working_htaccess', true)) {
734
+            return true;
735
+        }
736
+
737
+        $testContent = $this->createHtaccessTestFile($config);
738
+        if ($testContent === false) {
739
+            return false;
740
+        }
741
+
742
+        $fileName = '/htaccesstest.txt';
743
+        $testFile = $config->getSystemValueString('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
744
+
745
+        // accessing the file via http
746
+        $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
747
+        try {
748
+            $content = \OC::$server->get(IClientService::class)->newClient()->get($url)->getBody();
749
+        } catch (\Exception $e) {
750
+            $content = false;
751
+        }
752
+
753
+        if (str_starts_with($url, 'https:')) {
754
+            $url = 'http:' . substr($url, 6);
755
+        } else {
756
+            $url = 'https:' . substr($url, 5);
757
+        }
758
+
759
+        try {
760
+            $fallbackContent = \OC::$server->get(IClientService::class)->newClient()->get($url)->getBody();
761
+        } catch (\Exception $e) {
762
+            $fallbackContent = false;
763
+        }
764
+
765
+        // cleanup
766
+        @unlink($testFile);
767
+
768
+        /*
769 769
 		 * If the content is not equal to test content our .htaccess
770 770
 		 * is working as required
771 771
 		 */
772
-		return $content !== $testContent && $fallbackContent !== $testContent;
773
-	}
774
-
775
-	/**
776
-	 * Check if current locale is non-UTF8
777
-	 *
778
-	 * @return bool
779
-	 */
780
-	private static function isNonUTF8Locale() {
781
-		if (function_exists('escapeshellcmd')) {
782
-			return escapeshellcmd('§') === '';
783
-		} elseif (function_exists('escapeshellarg')) {
784
-			return escapeshellarg('§') === '\'\'';
785
-		} else {
786
-			return preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)) === 0;
787
-		}
788
-	}
789
-
790
-	/**
791
-	 * Check if the setlocale call does not work. This can happen if the right
792
-	 * local packages are not available on the server.
793
-	 *
794
-	 * @return bool
795
-	 */
796
-	public static function isSetLocaleWorking() {
797
-		if (self::isNonUTF8Locale()) {
798
-			// Borrowed from \Patchwork\Utf8\Bootup::initLocale
799
-			setlocale(LC_ALL, 'C.UTF-8', 'C');
800
-			setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0');
801
-
802
-			// Check again
803
-			if (self::isNonUTF8Locale()) {
804
-				return false;
805
-			}
806
-		}
807
-
808
-		return true;
809
-	}
810
-
811
-	/**
812
-	 * Check if it's possible to get the inline annotations
813
-	 *
814
-	 * @return bool
815
-	 */
816
-	public static function isAnnotationsWorking() {
817
-		if (PHP_VERSION_ID >= 80300) {
818
-			/** @psalm-suppress UndefinedMethod */
819
-			$reflection = \ReflectionMethod::createFromMethodName(__METHOD__);
820
-		} else {
821
-			$reflection = new \ReflectionMethod(__METHOD__);
822
-		}
823
-		$docs = $reflection->getDocComment();
824
-
825
-		return (is_string($docs) && strlen($docs) > 50);
826
-	}
827
-
828
-	/**
829
-	 * Check if the PHP module fileinfo is loaded.
830
-	 *
831
-	 * @return bool
832
-	 */
833
-	public static function fileInfoLoaded() {
834
-		return function_exists('finfo_open');
835
-	}
836
-
837
-	/**
838
-	 * clear all levels of output buffering
839
-	 *
840
-	 * @return void
841
-	 */
842
-	public static function obEnd() {
843
-		while (ob_get_level()) {
844
-			ob_end_clean();
845
-		}
846
-	}
847
-
848
-	/**
849
-	 * Checks whether the server is running on Mac OS X
850
-	 *
851
-	 * @return bool true if running on Mac OS X, false otherwise
852
-	 */
853
-	public static function runningOnMac() {
854
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
855
-	}
856
-
857
-	/**
858
-	 * Handles the case that there may not be a theme, then check if a "default"
859
-	 * theme exists and take that one
860
-	 *
861
-	 * @return string the theme
862
-	 */
863
-	public static function getTheme() {
864
-		$theme = \OC::$server->getSystemConfig()->getValue('theme', '');
865
-
866
-		if ($theme === '') {
867
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
868
-				$theme = 'default';
869
-			}
870
-		}
871
-
872
-		return $theme;
873
-	}
874
-
875
-	/**
876
-	 * Normalize a unicode string
877
-	 *
878
-	 * @param string $value a not normalized string
879
-	 * @return string The normalized string or the input if the normalization failed
880
-	 */
881
-	public static function normalizeUnicode(string $value): string {
882
-		if (Normalizer::isNormalized($value)) {
883
-			return $value;
884
-		}
885
-
886
-		$normalizedValue = Normalizer::normalize($value);
887
-		if ($normalizedValue === false) {
888
-			\OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
889
-			return $value;
890
-		}
891
-
892
-		return $normalizedValue;
893
-	}
894
-
895
-	/**
896
-	 * Check whether the instance needs to perform an upgrade,
897
-	 * either when the core version is higher or any app requires
898
-	 * an upgrade.
899
-	 *
900
-	 * @param \OC\SystemConfig $config
901
-	 * @return bool whether the core or any app needs an upgrade
902
-	 * @throws \OCP\HintException When the upgrade from the given version is not allowed
903
-	 */
904
-	public static function needUpgrade(\OC\SystemConfig $config) {
905
-		if ($config->getValue('installed', false)) {
906
-			$installedVersion = $config->getValue('version', '0.0.0');
907
-			$currentVersion = implode('.', \OCP\Util::getVersion());
908
-			$versionDiff = version_compare($currentVersion, $installedVersion);
909
-			if ($versionDiff > 0) {
910
-				return true;
911
-			} elseif ($config->getValue('debug', false) && $versionDiff < 0) {
912
-				// downgrade with debug
913
-				$installedMajor = explode('.', $installedVersion);
914
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
915
-				$currentMajor = explode('.', $currentVersion);
916
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
917
-				if ($installedMajor === $currentMajor) {
918
-					// Same major, allow downgrade for developers
919
-					return true;
920
-				} else {
921
-					// downgrade attempt, throw exception
922
-					throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
923
-				}
924
-			} elseif ($versionDiff < 0) {
925
-				// downgrade attempt, throw exception
926
-				throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
927
-			}
928
-
929
-			// also check for upgrades for apps (independently from the user)
930
-			$apps = \OC_App::getEnabledApps(false, true);
931
-			$shouldUpgrade = false;
932
-			foreach ($apps as $app) {
933
-				if (\OC_App::shouldUpgrade($app)) {
934
-					$shouldUpgrade = true;
935
-					break;
936
-				}
937
-			}
938
-			return $shouldUpgrade;
939
-		} else {
940
-			return false;
941
-		}
942
-	}
772
+        return $content !== $testContent && $fallbackContent !== $testContent;
773
+    }
774
+
775
+    /**
776
+     * Check if current locale is non-UTF8
777
+     *
778
+     * @return bool
779
+     */
780
+    private static function isNonUTF8Locale() {
781
+        if (function_exists('escapeshellcmd')) {
782
+            return escapeshellcmd('§') === '';
783
+        } elseif (function_exists('escapeshellarg')) {
784
+            return escapeshellarg('§') === '\'\'';
785
+        } else {
786
+            return preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)) === 0;
787
+        }
788
+    }
789
+
790
+    /**
791
+     * Check if the setlocale call does not work. This can happen if the right
792
+     * local packages are not available on the server.
793
+     *
794
+     * @return bool
795
+     */
796
+    public static function isSetLocaleWorking() {
797
+        if (self::isNonUTF8Locale()) {
798
+            // Borrowed from \Patchwork\Utf8\Bootup::initLocale
799
+            setlocale(LC_ALL, 'C.UTF-8', 'C');
800
+            setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0');
801
+
802
+            // Check again
803
+            if (self::isNonUTF8Locale()) {
804
+                return false;
805
+            }
806
+        }
807
+
808
+        return true;
809
+    }
810
+
811
+    /**
812
+     * Check if it's possible to get the inline annotations
813
+     *
814
+     * @return bool
815
+     */
816
+    public static function isAnnotationsWorking() {
817
+        if (PHP_VERSION_ID >= 80300) {
818
+            /** @psalm-suppress UndefinedMethod */
819
+            $reflection = \ReflectionMethod::createFromMethodName(__METHOD__);
820
+        } else {
821
+            $reflection = new \ReflectionMethod(__METHOD__);
822
+        }
823
+        $docs = $reflection->getDocComment();
824
+
825
+        return (is_string($docs) && strlen($docs) > 50);
826
+    }
827
+
828
+    /**
829
+     * Check if the PHP module fileinfo is loaded.
830
+     *
831
+     * @return bool
832
+     */
833
+    public static function fileInfoLoaded() {
834
+        return function_exists('finfo_open');
835
+    }
836
+
837
+    /**
838
+     * clear all levels of output buffering
839
+     *
840
+     * @return void
841
+     */
842
+    public static function obEnd() {
843
+        while (ob_get_level()) {
844
+            ob_end_clean();
845
+        }
846
+    }
847
+
848
+    /**
849
+     * Checks whether the server is running on Mac OS X
850
+     *
851
+     * @return bool true if running on Mac OS X, false otherwise
852
+     */
853
+    public static function runningOnMac() {
854
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
855
+    }
856
+
857
+    /**
858
+     * Handles the case that there may not be a theme, then check if a "default"
859
+     * theme exists and take that one
860
+     *
861
+     * @return string the theme
862
+     */
863
+    public static function getTheme() {
864
+        $theme = \OC::$server->getSystemConfig()->getValue('theme', '');
865
+
866
+        if ($theme === '') {
867
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
868
+                $theme = 'default';
869
+            }
870
+        }
871
+
872
+        return $theme;
873
+    }
874
+
875
+    /**
876
+     * Normalize a unicode string
877
+     *
878
+     * @param string $value a not normalized string
879
+     * @return string The normalized string or the input if the normalization failed
880
+     */
881
+    public static function normalizeUnicode(string $value): string {
882
+        if (Normalizer::isNormalized($value)) {
883
+            return $value;
884
+        }
885
+
886
+        $normalizedValue = Normalizer::normalize($value);
887
+        if ($normalizedValue === false) {
888
+            \OCP\Server::get(LoggerInterface::class)->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
889
+            return $value;
890
+        }
891
+
892
+        return $normalizedValue;
893
+    }
894
+
895
+    /**
896
+     * Check whether the instance needs to perform an upgrade,
897
+     * either when the core version is higher or any app requires
898
+     * an upgrade.
899
+     *
900
+     * @param \OC\SystemConfig $config
901
+     * @return bool whether the core or any app needs an upgrade
902
+     * @throws \OCP\HintException When the upgrade from the given version is not allowed
903
+     */
904
+    public static function needUpgrade(\OC\SystemConfig $config) {
905
+        if ($config->getValue('installed', false)) {
906
+            $installedVersion = $config->getValue('version', '0.0.0');
907
+            $currentVersion = implode('.', \OCP\Util::getVersion());
908
+            $versionDiff = version_compare($currentVersion, $installedVersion);
909
+            if ($versionDiff > 0) {
910
+                return true;
911
+            } elseif ($config->getValue('debug', false) && $versionDiff < 0) {
912
+                // downgrade with debug
913
+                $installedMajor = explode('.', $installedVersion);
914
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
915
+                $currentMajor = explode('.', $currentVersion);
916
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
917
+                if ($installedMajor === $currentMajor) {
918
+                    // Same major, allow downgrade for developers
919
+                    return true;
920
+                } else {
921
+                    // downgrade attempt, throw exception
922
+                    throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
923
+                }
924
+            } elseif ($versionDiff < 0) {
925
+                // downgrade attempt, throw exception
926
+                throw new \OCP\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
927
+            }
928
+
929
+            // also check for upgrades for apps (independently from the user)
930
+            $apps = \OC_App::getEnabledApps(false, true);
931
+            $shouldUpgrade = false;
932
+            foreach ($apps as $app) {
933
+                if (\OC_App::shouldUpgrade($app)) {
934
+                    $shouldUpgrade = true;
935
+                    break;
936
+                }
937
+            }
938
+            return $shouldUpgrade;
939
+        } else {
940
+            return false;
941
+        }
942
+    }
943 943
 }
Please login to merge, or discard this patch.