Completed
Push — master ( 23768d...c7d9e5 )
by Blizzz
16:22
created

OC::handleRequest()   F

Complexity

Conditions 22
Paths 408

Size

Total Lines 116
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 71
nc 408
nop 0
dl 0
loc 116
rs 3.5587
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 64 and the first side effect is on line 57.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Adam Williamson <[email protected]>
6
 * @author Andreas Fischer <[email protected]>
7
 * @author Arthur Schiwon <[email protected]>
8
 * @author Bart Visscher <[email protected]>
9
 * @author Bernhard Posselt <[email protected]>
10
 * @author Bjoern Schiessle <[email protected]>
11
 * @author Björn Schießle <[email protected]>
12
 * @author Christoph Wurst <[email protected]>
13
 * @author Damjan Georgievski <[email protected]>
14
 * @author davidgumberg <[email protected]>
15
 * @author Florin Peter <[email protected]>
16
 * @author Individual IT Services <[email protected]>
17
 * @author Jakob Sack <[email protected]>
18
 * @author Jan-Christoph Borchardt <[email protected]>
19
 * @author Joachim Sokolowski <[email protected]>
20
 * @author Joas Schilling <[email protected]>
21
 * @author John Molakvoæ (skjnldsv) <[email protected]>
22
 * @author Juan Pablo Villafáñez <[email protected]>
23
 * @author Jörn Friedrich Dreyer <[email protected]>
24
 * @author Ko- <[email protected]>
25
 * @author Lukas Reschke <[email protected]>
26
 * @author Michael Gapczynski <[email protected]>
27
 * @author Morris Jobke <[email protected]>
28
 * @author Owen Winkler <[email protected]>
29
 * @author Phil Davis <[email protected]>
30
 * @author Ramiro Aparicio <[email protected]>
31
 * @author Robin Appelman <[email protected]>
32
 * @author Robin McCorkell <[email protected]>
33
 * @author Roeland Jago Douma <[email protected]>
34
 * @author Sebastian Wessalowski <[email protected]>
35
 * @author Stefan Weil <[email protected]>
36
 * @author Thomas Müller <[email protected]>
37
 * @author Thomas Tanghus <[email protected]>
38
 * @author Vincent Petry <[email protected]>
39
 * @author Volkan Gezer <[email protected]>
40
 *
41
 * @license AGPL-3.0
42
 *
43
 * This code is free software: you can redistribute it and/or modify
44
 * it under the terms of the GNU Affero General Public License, version 3,
45
 * as published by the Free Software Foundation.
46
 *
47
 * This program is distributed in the hope that it will be useful,
48
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
49
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50
 * GNU Affero General Public License for more details.
51
 *
52
 * You should have received a copy of the GNU Affero General Public License, version 3,
53
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
54
 *
55
 */
56
57
require_once 'public/Constants.php';
58
59
/**
60
 * Class that is a namespace for all global OC variables
61
 * No, we can not put this class in its own file because it is used by
62
 * OC_autoload!
63
 */
64
class OC {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
65
	/**
66
	 * Associative array for autoloading. classname => filename
67
	 */
68
	public static $CLASSPATH = array();
69
	/**
70
	 * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
71
	 */
72
	public static $SERVERROOT = '';
73
	/**
74
	 * the current request path relative to the Nextcloud root (e.g. files/index.php)
75
	 */
76
	private static $SUBURI = '';
77
	/**
78
	 * the Nextcloud root path for http requests (e.g. nextcloud/)
79
	 */
80
	public static $WEBROOT = '';
81
	/**
82
	 * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
83
	 * web path in 'url'
84
	 */
85
	public static $APPSROOTS = array();
86
87
	/**
88
	 * @var string
89
	 */
90
	public static $configDir;
91
92
	/**
93
	 * requested app
94
	 */
95
	public static $REQUESTEDAPP = '';
96
97
	/**
98
	 * check if Nextcloud runs in cli mode
99
	 */
100
	public static $CLI = false;
101
102
	/**
103
	 * @var \OC\Autoloader $loader
104
	 */
105
	public static $loader = null;
106
107
	/** @var \Composer\Autoload\ClassLoader $composerAutoloader */
108
	public static $composerAutoloader = null;
109
110
	/**
111
	 * @var \OC\Server
112
	 */
113
	public static $server = null;
114
115
	/**
116
	 * @var \OC\Config
117
	 */
118
	private static $config = null;
119
120
	/**
121
	 * @throws \RuntimeException when the 3rdparty directory is missing or
122
	 * the app path list is empty or contains an invalid path
123
	 */
124
	public static function initPaths() {
0 ignored issues
show
Coding Style introduced by
initPaths uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
125
		if(defined('PHPUNIT_CONFIG_DIR')) {
126
			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
127
		} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
128
			self::$configDir = OC::$SERVERROOT . '/tests/config/';
129
		} elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
130
			self::$configDir = rtrim($dir, '/') . '/';
131
		} else {
132
			self::$configDir = OC::$SERVERROOT . '/config/';
133
		}
134
		self::$config = new \OC\Config(self::$configDir);
135
136
		OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
137
		/**
138
		 * FIXME: The following lines are required because we can't yet instantiate
139
		 *        \OC::$server->getRequest() since \OC::$server does not yet exist.
140
		 */
141
		$params = [
142
			'server' => [
143
				'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
144
				'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
145
			],
146
		];
147
		$fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
148
		$scriptName = $fakeRequest->getScriptName();
149
		if (substr($scriptName, -1) == '/') {
150
			$scriptName .= 'index.php';
151
			//make sure suburi follows the same rules as scriptName
152
			if (substr(OC::$SUBURI, -9) != 'index.php') {
153
				if (substr(OC::$SUBURI, -1) != '/') {
154
					OC::$SUBURI = OC::$SUBURI . '/';
155
				}
156
				OC::$SUBURI = OC::$SUBURI . 'index.php';
157
			}
158
		}
159
160
161
		if (OC::$CLI) {
162
			OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
163
		} else {
164
			if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
165
				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
166
167
				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
168
					OC::$WEBROOT = '/' . OC::$WEBROOT;
169
				}
170
			} else {
171
				// The scriptName is not ending with OC::$SUBURI
172
				// This most likely means that we are calling from CLI.
173
				// However some cron jobs still need to generate
174
				// a web URL, so we use overwritewebroot as a fallback.
175
				OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
176
			}
177
178
			// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
179
			// slash which is required by URL generation.
180
			if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
181
					substr($_SERVER['REQUEST_URI'], -1) !== '/') {
182
				header('Location: '.\OC::$WEBROOT.'/');
183
				exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method initPaths() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
184
			}
185
		}
186
187
		// search the apps folder
188
		$config_paths = self::$config->getValue('apps_paths', array());
189
		if (!empty($config_paths)) {
190
			foreach ($config_paths as $paths) {
191
				if (isset($paths['url']) && isset($paths['path'])) {
192
					$paths['url'] = rtrim($paths['url'], '/');
193
					$paths['path'] = rtrim($paths['path'], '/');
194
					OC::$APPSROOTS[] = $paths;
195
				}
196
			}
197
		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
198
			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
199
		} elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
200
			OC::$APPSROOTS[] = array(
201
				'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
202
				'url' => '/apps',
203
				'writable' => true
204
			);
205
		}
206
207
		if (empty(OC::$APPSROOTS)) {
208
			throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
209
				. ' or the folder above. You can also configure the location in the config.php file.');
210
		}
211
		$paths = array();
212
		foreach (OC::$APPSROOTS as $path) {
213
			$paths[] = $path['path'];
214
			if (!is_dir($path['path'])) {
215
				throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
216
					. ' Nextcloud folder or the folder above. You can also configure the location in the'
217
					. ' config.php file.', $path['path']));
218
			}
219
		}
220
221
		// set the right include path
222
		set_include_path(
223
			implode(PATH_SEPARATOR, $paths)
224
		);
225
	}
226
227
	public static function checkConfig() {
228
		$l = \OC::$server->getL10N('lib');
229
230
		// Create config if it does not already exist
231
		$configFilePath = self::$configDir .'/config.php';
232
		if(!file_exists($configFilePath)) {
233
			@touch($configFilePath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
234
		}
235
236
		// Check if config is writable
237
		$configFileWritable = is_writable($configFilePath);
238
		if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
239
			|| !$configFileWritable && \OCP\Util::needUpgrade()) {
240
241
			$urlGenerator = \OC::$server->getURLGenerator();
242
243
			if (self::$CLI) {
244
				echo $l->t('Cannot write into "config" directory!')."\n";
245
				echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
246
				echo "\n";
247
				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
248
				exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method checkConfig() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
249
			} else {
250
				OC_Template::printErrorPage(
251
					$l->t('Cannot write into "config" directory!'),
252
					$l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
253
					 [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
254
				);
255
			}
256
		}
257
	}
258
259
	public static function checkInstalled() {
260
		if (defined('OC_CONSOLE')) {
261
			return;
262
		}
263
		// Redirect to installer if not installed
264
		if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
265
			if (OC::$CLI) {
266
				throw new Exception('Not installed');
267
			} else {
268
				$url = OC::$WEBROOT . '/index.php';
269
				header('Location: ' . $url);
270
			}
271
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method checkInstalled() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
272
		}
273
	}
274
275
	public static function checkMaintenanceMode() {
276
		// Allow ajax update script to execute without being stopped
277
		if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
278
			// send http status 503
279
			header('HTTP/1.1 503 Service Temporarily Unavailable');
280
			header('Status: 503 Service Temporarily Unavailable');
281
			header('Retry-After: 120');
282
283
			// render error page
284
			$template = new OC_Template('', 'update.user', 'guest');
285
			OC_Util::addScript('maintenance-check');
286
			OC_Util::addStyle('core', 'guest');
287
			$template->printPage();
288
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method checkMaintenanceMode() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
289
		}
290
	}
291
292
	/**
293
	 * Prints the upgrade page
294
	 *
295
	 * @param \OC\SystemConfig $systemConfig
296
	 */
297
	private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
0 ignored issues
show
Coding Style introduced by
printUpgradePage uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
298
		$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
299
		$tooBig = false;
300
		if (!$disableWebUpdater) {
301
			$apps = \OC::$server->getAppManager();
302 View Code Duplication
			if ($apps->isInstalled('user_ldap')) {
303
				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
304
305
				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
306
					->from('ldap_user_mapping')
307
					->execute();
308
				$row = $result->fetch();
309
				$result->closeCursor();
310
311
				$tooBig = ($row['user_count'] > 50);
312
			}
313 View Code Duplication
			if (!$tooBig && $apps->isInstalled('user_saml')) {
314
				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
315
316
				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
317
					->from('user_saml_users')
318
					->execute();
319
				$row = $result->fetch();
320
				$result->closeCursor();
321
322
				$tooBig = ($row['user_count'] > 50);
323
			}
324
			if (!$tooBig) {
325
				// count users
326
				$stats = \OC::$server->getUserManager()->countUsers();
327
				$totalUsers = array_sum($stats);
328
				$tooBig = ($totalUsers > 50);
329
			}
330
		}
331
		$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
332
			$_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
333
334
		if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
335
			// send http status 503
336
			header('HTTP/1.1 503 Service Temporarily Unavailable');
337
			header('Status: 503 Service Temporarily Unavailable');
338
			header('Retry-After: 120');
339
340
			// render error page
341
			$template = new OC_Template('', 'update.use-cli', 'guest');
342
			$template->assign('productName', 'nextcloud'); // for now
343
			$template->assign('version', OC_Util::getVersionString());
344
			$template->assign('tooBig', $tooBig);
345
346
			$template->printPage();
347
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method printUpgradePage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
348
		}
349
350
		// check whether this is a core update or apps update
351
		$installedVersion = $systemConfig->getValue('version', '0.0.0');
352
		$currentVersion = implode('.', \OCP\Util::getVersion());
353
354
		// if not a core upgrade, then it's apps upgrade
355
		$isAppsOnlyUpgrade = (version_compare($currentVersion, $installedVersion, '='));
356
357
		$oldTheme = $systemConfig->getValue('theme');
358
		$systemConfig->setValue('theme', '');
359
		OC_Util::addScript('config'); // needed for web root
360
		OC_Util::addScript('update');
361
362
		/** @var \OC\App\AppManager $appManager */
363
		$appManager = \OC::$server->getAppManager();
364
365
		$tmpl = new OC_Template('', 'update.admin', 'guest');
366
		$tmpl->assign('version', OC_Util::getVersionString());
367
		$tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
368
369
		// get third party apps
370
		$ocVersion = \OCP\Util::getVersion();
371
		$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
0 ignored issues
show
Documentation introduced by
$ocVersion is of type array, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
372
		$incompatibleShippedApps = [];
373
		foreach ($incompatibleApps as $appInfo) {
374
			if ($appManager->isShipped($appInfo['id'])) {
375
				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
376
			}
377
		}
378
379
		if (!empty($incompatibleShippedApps)) {
380
			$l = \OC::$server->getL10N('core');
381
			$hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
382
			throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
383
		}
384
385
		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
0 ignored issues
show
Documentation introduced by
$ocVersion is of type array, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
386
		$tmpl->assign('incompatibleAppsList', $incompatibleApps);
387
		$tmpl->assign('productName', 'Nextcloud'); // for now
388
		$tmpl->assign('oldTheme', $oldTheme);
389
		$tmpl->printPage();
390
	}
391
392
	public static function initSession() {
0 ignored issues
show
Coding Style introduced by
initSession uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
393
		if(self::$server->getRequest()->getServerProtocol() === 'https') {
394
			ini_set('session.cookie_secure', true);
395
		}
396
397
		// prevents javascript from accessing php session cookies
398
		ini_set('session.cookie_httponly', 'true');
399
400
		// set the cookie path to the Nextcloud directory
401
		$cookie_path = OC::$WEBROOT ? : '/';
402
		ini_set('session.cookie_path', $cookie_path);
403
404
		// Let the session name be changed in the initSession Hook
405
		$sessionName = OC_Util::getInstanceId();
406
407
		try {
408
			// Allow session apps to create a custom session object
409
			$useCustomSession = false;
410
			$session = self::$server->getSession();
411
			OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
412
			if (!$useCustomSession) {
413
				// set the session name to the instance id - which is unique
414
				$session = new \OC\Session\Internal($sessionName);
415
			}
416
417
			$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
418
			$session = $cryptoWrapper->wrapSession($session);
419
			self::$server->setSession($session);
420
421
			// if session can't be started break with http 500 error
422
		} catch (Exception $e) {
423
			\OCP\Util::logException('base', $e);
424
			//show the user a detailed error page
425
			OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
426
			OC_Template::printExceptionErrorPage($e);
427
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method initSession() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
428
		}
429
430
		$sessionLifeTime = self::getSessionLifeTime();
431
432
		// session timeout
433
		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
434
			if (isset($_COOKIE[session_name()])) {
435
				setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
436
			}
437
			\OC::$server->getUserSession()->logout();
438
		}
439
440
		$session->set('LAST_ACTIVITY', time());
441
	}
442
443
	/**
444
	 * @return string
445
	 */
446
	private static function getSessionLifeTime() {
447
		return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
448
	}
449
450
	public static function loadAppClassPaths() {
451 View Code Duplication
		foreach (OC_App::getEnabledApps() as $app) {
452
			$appPath = OC_App::getAppPath($app);
453
			if ($appPath === false) {
454
				continue;
455
			}
456
457
			$file = $appPath . '/appinfo/classpath.php';
458
			if (file_exists($file)) {
459
				require_once $file;
460
			}
461
		}
462
	}
463
464
	/**
465
	 * Try to set some values to the required Nextcloud default
466
	 */
467
	public static function setRequiredIniValues() {
468
		@ini_set('default_charset', 'UTF-8');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
469
		@ini_set('gd.jpeg_ignore_warning', '1');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
470
	}
471
472
	/**
473
	 * Send the same site cookies
474
	 */
475 View Code Duplication
	private static function sendSameSiteCookies() {
476
		$cookieParams = session_get_cookie_params();
477
		$secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
478
		$policies = [
479
			'lax',
480
			'strict',
481
		];
482
483
		// Append __Host to the cookie if it meets the requirements
484
		$cookiePrefix = '';
485
		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
486
			$cookiePrefix = '__Host-';
487
		}
488
489
		foreach($policies as $policy) {
490
			header(
491
				sprintf(
492
					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
493
					$cookiePrefix,
494
					$policy,
495
					$cookieParams['path'],
496
					$policy
497
				),
498
				false
499
			);
500
		}
501
	}
502
503
	/**
504
	 * Same Site cookie to further mitigate CSRF attacks. This cookie has to
505
	 * be set in every request if cookies are sent to add a second level of
506
	 * defense against CSRF.
507
	 *
508
	 * If the cookie is not sent this will set the cookie and reload the page.
509
	 * We use an additional cookie since we want to protect logout CSRF and
510
	 * also we can't directly interfere with PHP's session mechanism.
511
	 */
512
	private static function performSameSiteCookieProtection() {
0 ignored issues
show
Coding Style introduced by
performSameSiteCookieProtection uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
513
		$request = \OC::$server->getRequest();
514
515
		// Some user agents are notorious and don't really properly follow HTTP
516
		// specifications. For those, have an automated opt-out. Since the protection
517
		// for remote.php is applied in base.php as starting point we need to opt out
518
		// here.
519
		$incompatibleUserAgents = [
520
			// OS X Finder
521
			'/^WebDAVFS/',
522
		];
523
		if($request->isUserAgent($incompatibleUserAgents)) {
524
			return;
525
		}
526
527
		if(count($_COOKIE) > 0) {
528
			$requestUri = $request->getScriptName();
529
			$processingScript = explode('/', $requestUri);
530
			$processingScript = $processingScript[count($processingScript)-1];
531
532
			// index.php routes are handled in the middleware
533
			if($processingScript === 'index.php') {
534
				return;
535
			}
536
537
			// All other endpoints require the lax and the strict cookie
538
			if(!$request->passesStrictCookieCheck()) {
539
				self::sendSameSiteCookies();
540
				// Debug mode gets access to the resources without strict cookie
541
				// due to the fact that the SabreDAV browser also lives there.
542
				if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
543
					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
544
					exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method performSameSiteCookieProtection() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
545
				}
546
			}
547
		} elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
548
			self::sendSameSiteCookies();
549
		}
550
	}
551
552
	public static function init() {
0 ignored issues
show
Coding Style introduced by
init uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
553
		// calculate the root directories
554
		OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
555
556
		// register autoloader
557
		$loaderStart = microtime(true);
558
		require_once __DIR__ . '/autoloader.php';
559
		self::$loader = new \OC\Autoloader([
560
			OC::$SERVERROOT . '/lib/private/legacy',
561
		]);
562
		if (defined('PHPUNIT_RUN')) {
563
			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
564
		}
565
		spl_autoload_register(array(self::$loader, 'load'));
566
		$loaderEnd = microtime(true);
567
568
		self::$CLI = (php_sapi_name() == 'cli');
569
570
		// Add default composer PSR-4 autoloader
571
		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
572
573
		try {
574
			self::initPaths();
575
			// setup 3rdparty autoloader
576
			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
577
			if (!file_exists($vendorAutoLoad)) {
578
				throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
579
			}
580
			require_once $vendorAutoLoad;
581
582
		} catch (\RuntimeException $e) {
583
			if (!self::$CLI) {
584
				$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
585
				$protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
586
				header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
587
			}
588
			// we can't use the template error page here, because this needs the
589
			// DI container which isn't available yet
590
			print($e->getMessage());
591
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
592
		}
593
594
		// setup the basic server
595
		self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
596
		\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
597
		\OC::$server->getEventLogger()->start('boot', 'Initialize');
598
599
		// Don't display errors and log them
600
		error_reporting(E_ALL | E_STRICT);
601
		@ini_set('display_errors', '0');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
602
		@ini_set('log_errors', '1');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
603
604
		if(!date_default_timezone_set('UTC')) {
605
			throw new \RuntimeException('Could not set timezone to UTC');
606
		};
607
608
		//try to configure php to enable big file uploads.
609
		//this doesn´t work always depending on the webserver and php configuration.
610
		//Let´s try to overwrite some defaults anyway
611
612
		//try to set the maximum execution time to 60min
613
		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
614
			@set_time_limit(3600);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
615
		}
616
		@ini_set('max_execution_time', '3600');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
617
		@ini_set('max_input_time', '3600');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
618
619
		//try to set the maximum filesize to 10G
620
		@ini_set('upload_max_filesize', '10G');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
621
		@ini_set('post_max_size', '10G');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
622
		@ini_set('file_uploads', '50');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
623
624
		self::setRequiredIniValues();
625
		self::handleAuthHeaders();
626
		self::registerAutoloaderCache();
627
628
		// initialize intl fallback is necessary
629
		\Patchwork\Utf8\Bootup::initIntl();
630
		OC_Util::isSetLocaleWorking();
631
632
		if (!defined('PHPUNIT_RUN')) {
633
			OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
634
			$debug = \OC::$server->getConfig()->getSystemValue('debug', false);
635
			OC\Log\ErrorHandler::register($debug);
636
		}
637
638
		\OC::$server->getEventLogger()->start('init_session', 'Initialize session');
639
		OC_App::loadApps(array('session'));
640
		if (!self::$CLI) {
641
			self::initSession();
642
		}
643
		\OC::$server->getEventLogger()->end('init_session');
644
		self::checkConfig();
645
		self::checkInstalled();
646
647
		OC_Response::addSecurityHeaders();
648
649
		self::performSameSiteCookieProtection();
650
651
		if (!defined('OC_CONSOLE')) {
652
			$errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
653
			if (count($errors) > 0) {
654
				if (self::$CLI) {
655
					// Convert l10n string into regular string for usage in database
656
					$staticErrors = [];
657
					foreach ($errors as $error) {
658
						echo $error['error'] . "\n";
659
						echo $error['hint'] . "\n\n";
660
						$staticErrors[] = [
661
							'error' => (string)$error['error'],
662
							'hint' => (string)$error['hint'],
663
						];
664
					}
665
666
					try {
667
						\OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
668
					} catch (\Exception $e) {
669
						echo('Writing to database failed');
670
					}
671
					exit(1);
0 ignored issues
show
Coding Style Compatibility introduced by
The method init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
672
				} else {
673
					OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
674
					OC_Util::addStyle('guest');
675
					OC_Template::printGuestPage('', 'error', array('errors' => $errors));
676
					exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
677
				}
678 View Code Duplication
			} elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
679
				\OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
680
			}
681
		}
682
		//try to set the session lifetime
683
		$sessionLifeTime = self::getSessionLifeTime();
684
		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
685
686
		$systemConfig = \OC::$server->getSystemConfig();
687
688
		// User and Groups
689
		if (!$systemConfig->getValue("installed", false)) {
690
			self::$server->getSession()->set('user_id', '');
691
		}
692
693
		OC_User::useBackend(new \OC\User\Database());
694
		\OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
695
696
		// Subscribe to the hook
697
		\OCP\Util::connectHook(
698
			'\OCA\Files_Sharing\API\Server2Server',
699
			'preLoginNameUsedAsUserName',
700
			'\OC\User\Database',
701
			'preLoginNameUsedAsUserName'
702
		);
703
704
		//setup extra user backends
705
		if (!\OCP\Util::needUpgrade()) {
706
			OC_User::setupBackends();
707
		} else {
708
			// Run upgrades in incognito mode
709
			OC_User::setIncognitoMode(true);
710
		}
711
712
		self::registerCleanupHooks();
713
		self::registerFilesystemHooks();
714
		self::registerShareHooks();
715
		self::registerEncryptionWrapper();
716
		self::registerEncryptionHooks();
717
		self::registerAccountHooks();
718
		self::registerSettingsHooks();
719
720
		$settings = new \OC\Settings\Application();
721
		$settings->register();
722
723
		//make sure temporary files are cleaned up
724
		$tmpManager = \OC::$server->getTempManager();
725
		register_shutdown_function(array($tmpManager, 'clean'));
726
		$lockProvider = \OC::$server->getLockingProvider();
727
		register_shutdown_function(array($lockProvider, 'releaseAll'));
728
729
		// Check whether the sample configuration has been copied
730
		if($systemConfig->getValue('copied_sample_config', false)) {
731
			$l = \OC::$server->getL10N('lib');
732
			header('HTTP/1.1 503 Service Temporarily Unavailable');
733
			header('Status: 503 Service Temporarily Unavailable');
734
			OC_Template::printErrorPage(
735
				$l->t('Sample configuration detected'),
736
				$l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php')
737
			);
738
			return;
739
		}
740
741
		$request = \OC::$server->getRequest();
742
		$host = $request->getInsecureServerHost();
743
		/**
744
		 * if the host passed in headers isn't trusted
745
		 * FIXME: Should not be in here at all :see_no_evil:
746
		 */
747
		if (!OC::$CLI
748
			// overwritehost is always trusted, workaround to not have to make
749
			// \OC\AppFramework\Http\Request::getOverwriteHost public
750
			&& self::$server->getConfig()->getSystemValue('overwritehost') === ''
751
			&& !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
752
			&& self::$server->getConfig()->getSystemValue('installed', false)
753
		) {
754
			// Allow access to CSS resources
755
			$isScssRequest = false;
756
			if(strpos($request->getPathInfo(), '/css/') === 0) {
757
				$isScssRequest = true;
758
			}
759
760
			if (!$isScssRequest) {
761
				header('HTTP/1.1 400 Bad Request');
762
				header('Status: 400 Bad Request');
763
764
				\OC::$server->getLogger()->warning(
765
					'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
766
					[
767
						'app' => 'core',
768
						'remoteAddress' => $request->getRemoteAddress(),
769
						'host' => $host,
770
					]
771
				);
772
773
				$tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
774
				$tmpl->assign('domain', $host);
775
				$tmpl->printPage();
776
777
				exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
778
			}
779
		}
780
		\OC::$server->getEventLogger()->end('boot');
781
	}
782
783
	/**
784
	 * register hooks for the cleanup of cache and bruteforce protection
785
	 */
786
	public static function registerCleanupHooks() {
787
		//don't try to do this before we are properly setup
788
		if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
789
790
			// NOTE: This will be replaced to use OCP
791
			$userSession = self::$server->getUserSession();
792
			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
793
				if (!defined('PHPUNIT_RUN')) {
794
					// reset brute force delay for this IP address and username
795
					$uid = \OC::$server->getUserSession()->getUser()->getUID();
796
					$request = \OC::$server->getRequest();
797
					$throttler = \OC::$server->getBruteForceThrottler();
798
					$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
0 ignored issues
show
Documentation introduced by
array('user' => $uid) is of type array<string,?,{"user":"?"}>, but the function expects a string.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
799
				}
800
801
				try {
802
					$cache = new \OC\Cache\File();
803
					$cache->gc();
804
				} catch (\OC\ServerNotAvailableException $e) {
805
					// not a GC exception, pass it on
806
					throw $e;
807
				} catch (\OC\ForbiddenException $e) {
808
					// filesystem blocked for this request, ignore
809
				} catch (\Exception $e) {
810
					// a GC exception should not prevent users from using OC,
811
					// so log the exception
812
					\OC::$server->getLogger()->warning('Exception when running cache gc: ' . $e->getMessage(), array('app' => 'core'));
813
				}
814
			});
815
		}
816
	}
817
818
	public static function registerSettingsHooks() {
819
		$dispatcher = \OC::$server->getEventDispatcher();
820
		$dispatcher->addListener(OCP\App\ManagerEvent::EVENT_APP_DISABLE, function($event) {
821
			/** @var \OCP\App\ManagerEvent $event */
822
			\OC::$server->getSettingsManager()->onAppDisabled($event->getAppID());
823
		});
824
		$dispatcher->addListener(OCP\App\ManagerEvent::EVENT_APP_UPDATE, function($event) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
825
			/** @var \OCP\App\ManagerEvent $event */
826
			$jobList = \OC::$server->getJobList();
827
			$job = 'OC\\Settings\\RemoveOrphaned';
828
			if(!($jobList->has($job, null))) {
829
				$jobList->add($job);
830
			}
831
		});
832
	}
833
834
	private static function registerEncryptionWrapper() {
835
		$manager = self::$server->getEncryptionManager();
836
		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
837
	}
838
839
	private static function registerEncryptionHooks() {
840
		$enabled = self::$server->getEncryptionManager()->isEnabled();
841
		if ($enabled) {
842
			\OCP\Util::connectHook('OCP\Share', 'post_shared', 'OC\Encryption\HookManager', 'postShared');
843
			\OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OC\Encryption\HookManager', 'postUnshared');
844
			\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OC\Encryption\HookManager', 'postRename');
845
			\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', 'OC\Encryption\HookManager', 'postRestore');
846
		}
847
	}
848
849
	private static function registerAccountHooks() {
850
		$hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
851
		\OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
852
	}
853
854
	/**
855
	 * register hooks for the filesystem
856
	 */
857
	public static function registerFilesystemHooks() {
858
		// Check for blacklisted files
859
		OC_Hook::connect('OC_Filesystem', 'write', 'OC\Files\Filesystem', 'isBlacklisted');
860
		OC_Hook::connect('OC_Filesystem', 'rename', 'OC\Files\Filesystem', 'isBlacklisted');
861
	}
862
863
	/**
864
	 * register hooks for sharing
865
	 */
866
	public static function registerShareHooks() {
867
		if (\OC::$server->getSystemConfig()->getValue('installed')) {
868
			OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share20\Hooks', 'post_deleteUser');
869
			OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OC\Share20\Hooks', 'post_removeFromGroup');
870
			OC_Hook::connect('OC_User', 'post_deleteGroup', 'OC\Share20\Hooks', 'post_deleteGroup');
871
		}
872
	}
873
874
	protected static function registerAutoloaderCache() {
875
		// The class loader takes an optional low-latency cache, which MUST be
876
		// namespaced. The instanceid is used for namespacing, but might be
877
		// unavailable at this point. Furthermore, it might not be possible to
878
		// generate an instanceid via \OC_Util::getInstanceId() because the
879
		// config file may not be writable. As such, we only register a class
880
		// loader cache if instanceid is available without trying to create one.
881
		$instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
882
		if ($instanceId) {
883
			try {
884
				$memcacheFactory = \OC::$server->getMemCacheFactory();
885
				self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
0 ignored issues
show
Documentation introduced by
$memcacheFactory->createLocal('Autoloader') is of type object<OCP\ICache>, but the function expects a null|object<OC\Memcache\Cache>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
886
			} catch (\Exception $ex) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
887
			}
888
		}
889
	}
890
891
	/**
892
	 * Handle the request
893
	 */
894
	public static function handleRequest() {
0 ignored issues
show
Coding Style introduced by
handleRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
handleRequest uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
895
896
		\OC::$server->getEventLogger()->start('handle_request', 'Handle request');
897
		$systemConfig = \OC::$server->getSystemConfig();
898
		// load all the classpaths from the enabled apps so they are available
899
		// in the routing files of each app
900
		OC::loadAppClassPaths();
901
902
		// Check if Nextcloud is installed or in maintenance (update) mode
903
		if (!$systemConfig->getValue('installed', false)) {
904
			\OC::$server->getSession()->clear();
905
			$setupHelper = new OC\Setup(
906
				$systemConfig,
907
				\OC::$server->getIniWrapper(),
908
				\OC::$server->getL10N('lib'),
909
				\OC::$server->query(\OCP\Defaults::class),
910
				\OC::$server->getLogger(),
911
				\OC::$server->getSecureRandom(),
912
				\OC::$server->query(\OC\Installer::class)
913
			);
914
			$controller = new OC\Core\Controller\SetupController($setupHelper);
915
			$controller->run($_POST);
916
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method handleRequest() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
917
		}
918
919
		$request = \OC::$server->getRequest();
920
		$requestPath = $request->getRawPathInfo();
921
		if ($requestPath === '/heartbeat') {
922
			return;
923
		}
924
		if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
925
			self::checkMaintenanceMode();
926
927
			if (\OCP\Util::needUpgrade()) {
928
				if (function_exists('opcache_reset')) {
929
					opcache_reset();
930
				}
931
				if (!$systemConfig->getValue('maintenance', false)) {
932
					self::printUpgradePage($systemConfig);
933
					exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method handleRequest() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
934
				}
935
			}
936
		}
937
938
		// emergency app disabling
939
		if ($requestPath === '/disableapp'
940
			&& $request->getMethod() === 'POST'
941
			&& ((array)$request->getParam('appid')) !== ''
942
		) {
943
			\OCP\JSON::callCheck();
944
			\OCP\JSON::checkAdminUser();
945
			$appIds = (array)$request->getParam('appid');
946
			foreach($appIds as $appId) {
947
				$appId = \OC_App::cleanAppId($appId);
948
				\OC_App::disable($appId);
949
			}
950
			\OC_JSON::success();
951
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method handleRequest() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
952
		}
953
954
		// Always load authentication apps
955
		OC_App::loadApps(['authentication']);
956
957
		// Load minimum set of apps
958
		if (!\OCP\Util::needUpgrade()
959
			&& !$systemConfig->getValue('maintenance', false)) {
960
			// For logged-in users: Load everything
961
			if(\OC::$server->getUserSession()->isLoggedIn()) {
962
				OC_App::loadApps();
963
			} else {
964
				// For guests: Load only filesystem and logging
965
				OC_App::loadApps(array('filesystem', 'logging'));
966
				self::handleLogin($request);
967
			}
968
		}
969
970
		if (!self::$CLI) {
971
			try {
972
				if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
973
					OC_App::loadApps(array('filesystem', 'logging'));
974
					OC_App::loadApps();
975
				}
976
				OC_Util::setupFS();
977
				OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
978
				return;
979
			} catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\Routin...sourceNotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
980
				//header('HTTP/1.0 404 Not Found');
981
			} catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\Routin...thodNotAllowedException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
982
				OC_Response::setStatus(405);
983
				return;
984
			}
985
		}
986
987
		// Handle WebDAV
988
		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
989
			// not allowed any more to prevent people
990
			// mounting this root directly.
991
			// Users need to mount remote.php/webdav instead.
992
			header('HTTP/1.1 405 Method Not Allowed');
993
			header('Status: 405 Method Not Allowed');
994
			return;
995
		}
996
997
		// Someone is logged in
998
		if (\OC::$server->getUserSession()->isLoggedIn()) {
999
			OC_App::loadApps();
1000
			OC_User::setupBackends();
1001
			OC_Util::setupFS();
1002
			// FIXME
1003
			// Redirect to default application
1004
			OC_Util::redirectToDefaultPage();
1005
		} else {
1006
			// Not handled and not logged in
1007
			header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1008
		}
1009
	}
1010
1011
	/**
1012
	 * Check login: apache auth, auth token, basic auth
1013
	 *
1014
	 * @param OCP\IRequest $request
1015
	 * @return boolean
1016
	 */
1017
	static function handleLogin(OCP\IRequest $request) {
0 ignored issues
show
Coding Style introduced by
handleLogin uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1018
		$userSession = self::$server->getUserSession();
1019
		if (OC_User::handleApacheAuth()) {
1020
			return true;
1021
		}
1022
		if ($userSession->tryTokenLogin($request)) {
1023
			return true;
1024
		}
1025
		if (isset($_COOKIE['nc_username'])
1026
			&& isset($_COOKIE['nc_token'])
1027
			&& isset($_COOKIE['nc_session_id'])
1028
			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1029
			return true;
1030
		}
1031
		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1032
			return true;
1033
		}
1034
		return false;
1035
	}
1036
1037
	protected static function handleAuthHeaders() {
0 ignored issues
show
Coding Style introduced by
handleAuthHeaders uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1038
		//copy http auth headers for apache+php-fcgid work around
1039
		if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1040
			$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1041
		}
1042
1043
		// Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1044
		$vars = array(
1045
			'HTTP_AUTHORIZATION', // apache+php-cgi work around
1046
			'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1047
		);
1048
		foreach ($vars as $var) {
1049
			if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1050
				list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1051
				$_SERVER['PHP_AUTH_USER'] = $name;
1052
				$_SERVER['PHP_AUTH_PW'] = $password;
1053
				break;
1054
			}
1055
		}
1056
	}
1057
}
1058
1059
OC::init();
1060