Passed
Push — master ( d0cf20...c1d359 )
by John
14:05 queued 12s
created
core/Command/Upgrade.php 2 patches
Indentation   +215 added lines, -215 removed lines patch added patch discarded remove patch
@@ -46,236 +46,236 @@
 block discarded – undo
46 46
 use Symfony\Component\EventDispatcher\GenericEvent;
47 47
 
48 48
 class Upgrade extends Command {
49
-	public const ERROR_SUCCESS = 0;
50
-	public const ERROR_NOT_INSTALLED = 1;
51
-	public const ERROR_MAINTENANCE_MODE = 2;
52
-	public const ERROR_UP_TO_DATE = 0;
53
-	public const ERROR_INVALID_ARGUMENTS = 4;
54
-	public const ERROR_FAILURE = 5;
49
+    public const ERROR_SUCCESS = 0;
50
+    public const ERROR_NOT_INSTALLED = 1;
51
+    public const ERROR_MAINTENANCE_MODE = 2;
52
+    public const ERROR_UP_TO_DATE = 0;
53
+    public const ERROR_INVALID_ARGUMENTS = 4;
54
+    public const ERROR_FAILURE = 5;
55 55
 
56
-	/** @var IConfig */
57
-	private $config;
56
+    /** @var IConfig */
57
+    private $config;
58 58
 
59
-	/** @var LoggerInterface */
60
-	private $logger;
59
+    /** @var LoggerInterface */
60
+    private $logger;
61 61
 
62
-	/** @var Installer */
63
-	private $installer;
62
+    /** @var Installer */
63
+    private $installer;
64 64
 
65
-	public function __construct(IConfig $config, LoggerInterface $logger, Installer $installer) {
66
-		parent::__construct();
67
-		$this->config = $config;
68
-		$this->logger = $logger;
69
-		$this->installer = $installer;
70
-	}
65
+    public function __construct(IConfig $config, LoggerInterface $logger, Installer $installer) {
66
+        parent::__construct();
67
+        $this->config = $config;
68
+        $this->logger = $logger;
69
+        $this->installer = $installer;
70
+    }
71 71
 
72
-	protected function configure() {
73
-		$this
74
-			->setName('upgrade')
75
-			->setDescription('run upgrade routines after installation of a new release. The release has to be installed before.');
76
-	}
72
+    protected function configure() {
73
+        $this
74
+            ->setName('upgrade')
75
+            ->setDescription('run upgrade routines after installation of a new release. The release has to be installed before.');
76
+    }
77 77
 
78
-	/**
79
-	 * Execute the upgrade command
80
-	 *
81
-	 * @param InputInterface $input input interface
82
-	 * @param OutputInterface $output output interface
83
-	 */
84
-	protected function execute(InputInterface $input, OutputInterface $output): int {
85
-		if (Util::needUpgrade()) {
86
-			if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
87
-				// Prepend each line with a little timestamp
88
-				$timestampFormatter = new TimestampFormatter($this->config, $output->getFormatter());
89
-				$output->setFormatter($timestampFormatter);
90
-			}
78
+    /**
79
+     * Execute the upgrade command
80
+     *
81
+     * @param InputInterface $input input interface
82
+     * @param OutputInterface $output output interface
83
+     */
84
+    protected function execute(InputInterface $input, OutputInterface $output): int {
85
+        if (Util::needUpgrade()) {
86
+            if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
87
+                // Prepend each line with a little timestamp
88
+                $timestampFormatter = new TimestampFormatter($this->config, $output->getFormatter());
89
+                $output->setFormatter($timestampFormatter);
90
+            }
91 91
 
92
-			$self = $this;
93
-			$updater = new Updater(
94
-					$this->config,
95
-					\OC::$server->getIntegrityCodeChecker(),
96
-					$this->logger,
97
-					$this->installer
98
-			);
92
+            $self = $this;
93
+            $updater = new Updater(
94
+                    $this->config,
95
+                    \OC::$server->getIntegrityCodeChecker(),
96
+                    $this->logger,
97
+                    $this->installer
98
+            );
99 99
 
100
-			$dispatcher = \OC::$server->getEventDispatcher();
101
-			$progress = new ProgressBar($output);
102
-			$progress->setFormat(" %message%\n %current%/%max% [%bar%] %percent:3s%%");
103
-			$listener = function ($event) use ($progress, $output) {
104
-				if ($event instanceof GenericEvent) {
105
-					$message = $event->getSubject();
106
-					if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
107
-						$output->writeln(' Checking table ' . $message);
108
-					} else {
109
-						if (strlen($message) > 60) {
110
-							$message = substr($message, 0, 57) . '...';
111
-						}
112
-						$progress->setMessage($message);
113
-						if ($event[0] === 1) {
114
-							$output->writeln('');
115
-							$progress->start($event[1]);
116
-						}
117
-						$progress->setProgress($event[0]);
118
-						if ($event[0] === $event[1]) {
119
-							$progress->setMessage('Done');
120
-							$progress->finish();
121
-							$output->writeln('');
122
-						}
123
-					}
124
-				}
125
-			};
126
-			$repairListener = function ($event) use ($progress, $output) {
127
-				if (!$event instanceof GenericEvent) {
128
-					return;
129
-				}
130
-				switch ($event->getSubject()) {
131
-					case '\OC\Repair::startProgress':
132
-						$progress->setMessage('Starting ...');
133
-						$output->writeln($event->getArgument(1));
134
-						$output->writeln('');
135
-						$progress->start($event->getArgument(0));
136
-						break;
137
-					case '\OC\Repair::advance':
138
-						$desc = $event->getArgument(1);
139
-						if (!empty($desc)) {
140
-							$progress->setMessage($desc);
141
-						}
142
-						$progress->advance($event->getArgument(0));
100
+            $dispatcher = \OC::$server->getEventDispatcher();
101
+            $progress = new ProgressBar($output);
102
+            $progress->setFormat(" %message%\n %current%/%max% [%bar%] %percent:3s%%");
103
+            $listener = function ($event) use ($progress, $output) {
104
+                if ($event instanceof GenericEvent) {
105
+                    $message = $event->getSubject();
106
+                    if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
107
+                        $output->writeln(' Checking table ' . $message);
108
+                    } else {
109
+                        if (strlen($message) > 60) {
110
+                            $message = substr($message, 0, 57) . '...';
111
+                        }
112
+                        $progress->setMessage($message);
113
+                        if ($event[0] === 1) {
114
+                            $output->writeln('');
115
+                            $progress->start($event[1]);
116
+                        }
117
+                        $progress->setProgress($event[0]);
118
+                        if ($event[0] === $event[1]) {
119
+                            $progress->setMessage('Done');
120
+                            $progress->finish();
121
+                            $output->writeln('');
122
+                        }
123
+                    }
124
+                }
125
+            };
126
+            $repairListener = function ($event) use ($progress, $output) {
127
+                if (!$event instanceof GenericEvent) {
128
+                    return;
129
+                }
130
+                switch ($event->getSubject()) {
131
+                    case '\OC\Repair::startProgress':
132
+                        $progress->setMessage('Starting ...');
133
+                        $output->writeln($event->getArgument(1));
134
+                        $output->writeln('');
135
+                        $progress->start($event->getArgument(0));
136
+                        break;
137
+                    case '\OC\Repair::advance':
138
+                        $desc = $event->getArgument(1);
139
+                        if (!empty($desc)) {
140
+                            $progress->setMessage($desc);
141
+                        }
142
+                        $progress->advance($event->getArgument(0));
143 143
 
144
-						break;
145
-					case '\OC\Repair::finishProgress':
146
-						$progress->setMessage('Done');
147
-						$progress->finish();
148
-						$output->writeln('');
149
-						break;
150
-					case '\OC\Repair::step':
151
-						if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
152
-							$output->writeln('<info>Repair step: ' . $event->getArgument(0) . '</info>');
153
-						}
154
-						break;
155
-					case '\OC\Repair::info':
156
-						if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
157
-							$output->writeln('<info>Repair info: ' . $event->getArgument(0) . '</info>');
158
-						}
159
-						break;
160
-					case '\OC\Repair::warning':
161
-						$output->writeln('<error>Repair warning: ' . $event->getArgument(0) . '</error>');
162
-						break;
163
-					case '\OC\Repair::error':
164
-						$output->writeln('<error>Repair error: ' . $event->getArgument(0) . '</error>');
165
-						break;
166
-				}
167
-			};
144
+                        break;
145
+                    case '\OC\Repair::finishProgress':
146
+                        $progress->setMessage('Done');
147
+                        $progress->finish();
148
+                        $output->writeln('');
149
+                        break;
150
+                    case '\OC\Repair::step':
151
+                        if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
152
+                            $output->writeln('<info>Repair step: ' . $event->getArgument(0) . '</info>');
153
+                        }
154
+                        break;
155
+                    case '\OC\Repair::info':
156
+                        if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
157
+                            $output->writeln('<info>Repair info: ' . $event->getArgument(0) . '</info>');
158
+                        }
159
+                        break;
160
+                    case '\OC\Repair::warning':
161
+                        $output->writeln('<error>Repair warning: ' . $event->getArgument(0) . '</error>');
162
+                        break;
163
+                    case '\OC\Repair::error':
164
+                        $output->writeln('<error>Repair error: ' . $event->getArgument(0) . '</error>');
165
+                        break;
166
+                }
167
+            };
168 168
 
169
-			$dispatcher->addListener('\OC\DB\Migrator::executeSql', $listener);
170
-			$dispatcher->addListener('\OC\DB\Migrator::checkTable', $listener);
171
-			$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
172
-			$dispatcher->addListener('\OC\Repair::advance', $repairListener);
173
-			$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
174
-			$dispatcher->addListener('\OC\Repair::step', $repairListener);
175
-			$dispatcher->addListener('\OC\Repair::info', $repairListener);
176
-			$dispatcher->addListener('\OC\Repair::warning', $repairListener);
177
-			$dispatcher->addListener('\OC\Repair::error', $repairListener);
169
+            $dispatcher->addListener('\OC\DB\Migrator::executeSql', $listener);
170
+            $dispatcher->addListener('\OC\DB\Migrator::checkTable', $listener);
171
+            $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
172
+            $dispatcher->addListener('\OC\Repair::advance', $repairListener);
173
+            $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
174
+            $dispatcher->addListener('\OC\Repair::step', $repairListener);
175
+            $dispatcher->addListener('\OC\Repair::info', $repairListener);
176
+            $dispatcher->addListener('\OC\Repair::warning', $repairListener);
177
+            $dispatcher->addListener('\OC\Repair::error', $repairListener);
178 178
 
179 179
 
180
-			$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($output) {
181
-				$output->writeln('<info>Turned on maintenance mode</info>');
182
-			});
183
-			$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($output) {
184
-				$output->writeln('<info>Turned off maintenance mode</info>');
185
-			});
186
-			$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($output) {
187
-				$output->writeln('<info>Maintenance mode is kept active</info>');
188
-			});
189
-			$updater->listen('\OC\Updater', 'updateEnd',
190
-				function ($success) use ($output, $self) {
191
-					if ($success) {
192
-						$message = "<info>Update successful</info>";
193
-					} else {
194
-						$message = "<error>Update failed</error>";
195
-					}
196
-					$output->writeln($message);
197
-				});
198
-			$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($output) {
199
-				$output->writeln('<info>Updating database schema</info>');
200
-			});
201
-			$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output) {
202
-				$output->writeln('<info>Updated database</info>');
203
-			});
204
-			$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output) {
205
-				$output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>');
206
-			});
207
-			$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($output) {
208
-				$output->writeln('<info>Checking for update of app ' . $app . ' in appstore</info>');
209
-			});
210
-			$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($output) {
211
-				$output->writeln('<info>Update app ' . $app . ' from App Store</info>');
212
-			});
213
-			$updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($output) {
214
-				$output->writeln('<info>Checked for update of app "' . $app . '" in App Store </info>');
215
-			});
216
-			$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($output) {
217
-				$output->writeln("<info>Checking whether the database schema for <$app> can be updated (this can take a long time depending on the database size)</info>");
218
-			});
219
-			$updater->listen('\OC\Updater', 'appUpgradeStarted', function ($app, $version) use ($output) {
220
-				$output->writeln("<info>Updating <$app> ...</info>");
221
-			});
222
-			$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) {
223
-				$output->writeln("<info>Updated <$app> to $version</info>");
224
-			});
225
-			$updater->listen('\OC\Updater', 'failure', function ($message) use ($output, $self) {
226
-				$output->writeln("<error>$message</error>");
227
-			});
228
-			$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($output) {
229
-				$output->writeln("<info>Setting log level to debug</info>");
230
-			});
231
-			$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($output) {
232
-				$output->writeln("<info>Resetting log level</info>");
233
-			});
234
-			$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($output) {
235
-				$output->writeln("<info>Starting code integrity check...</info>");
236
-			});
237
-			$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($output) {
238
-				$output->writeln("<info>Finished code integrity check</info>");
239
-			});
180
+            $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($output) {
181
+                $output->writeln('<info>Turned on maintenance mode</info>');
182
+            });
183
+            $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($output) {
184
+                $output->writeln('<info>Turned off maintenance mode</info>');
185
+            });
186
+            $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($output) {
187
+                $output->writeln('<info>Maintenance mode is kept active</info>');
188
+            });
189
+            $updater->listen('\OC\Updater', 'updateEnd',
190
+                function ($success) use ($output, $self) {
191
+                    if ($success) {
192
+                        $message = "<info>Update successful</info>";
193
+                    } else {
194
+                        $message = "<error>Update failed</error>";
195
+                    }
196
+                    $output->writeln($message);
197
+                });
198
+            $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($output) {
199
+                $output->writeln('<info>Updating database schema</info>');
200
+            });
201
+            $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output) {
202
+                $output->writeln('<info>Updated database</info>');
203
+            });
204
+            $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output) {
205
+                $output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>');
206
+            });
207
+            $updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($output) {
208
+                $output->writeln('<info>Checking for update of app ' . $app . ' in appstore</info>');
209
+            });
210
+            $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($output) {
211
+                $output->writeln('<info>Update app ' . $app . ' from App Store</info>');
212
+            });
213
+            $updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($output) {
214
+                $output->writeln('<info>Checked for update of app "' . $app . '" in App Store </info>');
215
+            });
216
+            $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($output) {
217
+                $output->writeln("<info>Checking whether the database schema for <$app> can be updated (this can take a long time depending on the database size)</info>");
218
+            });
219
+            $updater->listen('\OC\Updater', 'appUpgradeStarted', function ($app, $version) use ($output) {
220
+                $output->writeln("<info>Updating <$app> ...</info>");
221
+            });
222
+            $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) {
223
+                $output->writeln("<info>Updated <$app> to $version</info>");
224
+            });
225
+            $updater->listen('\OC\Updater', 'failure', function ($message) use ($output, $self) {
226
+                $output->writeln("<error>$message</error>");
227
+            });
228
+            $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($output) {
229
+                $output->writeln("<info>Setting log level to debug</info>");
230
+            });
231
+            $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($output) {
232
+                $output->writeln("<info>Resetting log level</info>");
233
+            });
234
+            $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($output) {
235
+                $output->writeln("<info>Starting code integrity check...</info>");
236
+            });
237
+            $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($output) {
238
+                $output->writeln("<info>Finished code integrity check</info>");
239
+            });
240 240
 
241
-			$success = $updater->upgrade();
241
+            $success = $updater->upgrade();
242 242
 
243
-			$this->postUpgradeCheck($input, $output);
243
+            $this->postUpgradeCheck($input, $output);
244 244
 
245
-			if (!$success) {
246
-				return self::ERROR_FAILURE;
247
-			}
245
+            if (!$success) {
246
+                return self::ERROR_FAILURE;
247
+            }
248 248
 
249
-			return self::ERROR_SUCCESS;
250
-		} elseif ($this->config->getSystemValueBool('maintenance')) {
251
-			//Possible scenario: Nextcloud core is updated but an app failed
252
-			$output->writeln('<comment>Nextcloud is in maintenance mode</comment>');
253
-			$output->write('<comment>Maybe an upgrade is already in process. Please check the '
254
-				. 'logfile (data/nextcloud.log). If you want to re-run the '
255
-				. 'upgrade procedure, remove the "maintenance mode" from '
256
-				. 'config.php and call this script again.</comment>'
257
-				, true);
258
-			return self::ERROR_MAINTENANCE_MODE;
259
-		} else {
260
-			$output->writeln('<info>Nextcloud is already latest version</info>');
261
-			return self::ERROR_UP_TO_DATE;
262
-		}
263
-	}
249
+            return self::ERROR_SUCCESS;
250
+        } elseif ($this->config->getSystemValueBool('maintenance')) {
251
+            //Possible scenario: Nextcloud core is updated but an app failed
252
+            $output->writeln('<comment>Nextcloud is in maintenance mode</comment>');
253
+            $output->write('<comment>Maybe an upgrade is already in process. Please check the '
254
+                . 'logfile (data/nextcloud.log). If you want to re-run the '
255
+                . 'upgrade procedure, remove the "maintenance mode" from '
256
+                . 'config.php and call this script again.</comment>'
257
+                , true);
258
+            return self::ERROR_MAINTENANCE_MODE;
259
+        } else {
260
+            $output->writeln('<info>Nextcloud is already latest version</info>');
261
+            return self::ERROR_UP_TO_DATE;
262
+        }
263
+    }
264 264
 
265
-	/**
266
-	 * Perform a post upgrade check (specific to the command line tool)
267
-	 *
268
-	 * @param InputInterface $input input interface
269
-	 * @param OutputInterface $output output interface
270
-	 */
271
-	protected function postUpgradeCheck(InputInterface $input, OutputInterface $output) {
272
-		$trustedDomains = $this->config->getSystemValue('trusted_domains', []);
273
-		if (empty($trustedDomains)) {
274
-			$output->write(
275
-				'<warning>The setting "trusted_domains" could not be ' .
276
-				'set automatically by the upgrade script, ' .
277
-				'please set it manually</warning>'
278
-			);
279
-		}
280
-	}
265
+    /**
266
+     * Perform a post upgrade check (specific to the command line tool)
267
+     *
268
+     * @param InputInterface $input input interface
269
+     * @param OutputInterface $output output interface
270
+     */
271
+    protected function postUpgradeCheck(InputInterface $input, OutputInterface $output) {
272
+        $trustedDomains = $this->config->getSystemValue('trusted_domains', []);
273
+        if (empty($trustedDomains)) {
274
+            $output->write(
275
+                '<warning>The setting "trusted_domains" could not be ' .
276
+                'set automatically by the upgrade script, ' .
277
+                'please set it manually</warning>'
278
+            );
279
+        }
280
+    }
281 281
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -100,14 +100,14 @@  discard block
 block discarded – undo
100 100
 			$dispatcher = \OC::$server->getEventDispatcher();
101 101
 			$progress = new ProgressBar($output);
102 102
 			$progress->setFormat(" %message%\n %current%/%max% [%bar%] %percent:3s%%");
103
-			$listener = function ($event) use ($progress, $output) {
103
+			$listener = function($event) use ($progress, $output) {
104 104
 				if ($event instanceof GenericEvent) {
105 105
 					$message = $event->getSubject();
106 106
 					if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
107
-						$output->writeln(' Checking table ' . $message);
107
+						$output->writeln(' Checking table '.$message);
108 108
 					} else {
109 109
 						if (strlen($message) > 60) {
110
-							$message = substr($message, 0, 57) . '...';
110
+							$message = substr($message, 0, 57).'...';
111 111
 						}
112 112
 						$progress->setMessage($message);
113 113
 						if ($event[0] === 1) {
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
 					}
124 124
 				}
125 125
 			};
126
-			$repairListener = function ($event) use ($progress, $output) {
126
+			$repairListener = function($event) use ($progress, $output) {
127 127
 				if (!$event instanceof GenericEvent) {
128 128
 					return;
129 129
 				}
@@ -149,19 +149,19 @@  discard block
 block discarded – undo
149 149
 						break;
150 150
 					case '\OC\Repair::step':
151 151
 						if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
152
-							$output->writeln('<info>Repair step: ' . $event->getArgument(0) . '</info>');
152
+							$output->writeln('<info>Repair step: '.$event->getArgument(0).'</info>');
153 153
 						}
154 154
 						break;
155 155
 					case '\OC\Repair::info':
156 156
 						if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
157
-							$output->writeln('<info>Repair info: ' . $event->getArgument(0) . '</info>');
157
+							$output->writeln('<info>Repair info: '.$event->getArgument(0).'</info>');
158 158
 						}
159 159
 						break;
160 160
 					case '\OC\Repair::warning':
161
-						$output->writeln('<error>Repair warning: ' . $event->getArgument(0) . '</error>');
161
+						$output->writeln('<error>Repair warning: '.$event->getArgument(0).'</error>');
162 162
 						break;
163 163
 					case '\OC\Repair::error':
164
-						$output->writeln('<error>Repair error: ' . $event->getArgument(0) . '</error>');
164
+						$output->writeln('<error>Repair error: '.$event->getArgument(0).'</error>');
165 165
 						break;
166 166
 				}
167 167
 			};
@@ -177,17 +177,17 @@  discard block
 block discarded – undo
177 177
 			$dispatcher->addListener('\OC\Repair::error', $repairListener);
178 178
 
179 179
 
180
-			$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($output) {
180
+			$updater->listen('\OC\Updater', 'maintenanceEnabled', function() use ($output) {
181 181
 				$output->writeln('<info>Turned on maintenance mode</info>');
182 182
 			});
183
-			$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($output) {
183
+			$updater->listen('\OC\Updater', 'maintenanceDisabled', function() use ($output) {
184 184
 				$output->writeln('<info>Turned off maintenance mode</info>');
185 185
 			});
186
-			$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($output) {
186
+			$updater->listen('\OC\Updater', 'maintenanceActive', function() use ($output) {
187 187
 				$output->writeln('<info>Maintenance mode is kept active</info>');
188 188
 			});
189 189
 			$updater->listen('\OC\Updater', 'updateEnd',
190
-				function ($success) use ($output, $self) {
190
+				function($success) use ($output, $self) {
191 191
 					if ($success) {
192 192
 						$message = "<info>Update successful</info>";
193 193
 					} else {
@@ -195,46 +195,46 @@  discard block
 block discarded – undo
195 195
 					}
196 196
 					$output->writeln($message);
197 197
 				});
198
-			$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($output) {
198
+			$updater->listen('\OC\Updater', 'dbUpgradeBefore', function() use ($output) {
199 199
 				$output->writeln('<info>Updating database schema</info>');
200 200
 			});
201
-			$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output) {
201
+			$updater->listen('\OC\Updater', 'dbUpgrade', function() use ($output) {
202 202
 				$output->writeln('<info>Updated database</info>');
203 203
 			});
204
-			$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output) {
205
-				$output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>');
204
+			$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use ($output) {
205
+				$output->writeln('<comment>Disabled incompatible app: '.$app.'</comment>');
206 206
 			});
207
-			$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($output) {
208
-				$output->writeln('<info>Checking for update of app ' . $app . ' in appstore</info>');
207
+			$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use ($output) {
208
+				$output->writeln('<info>Checking for update of app '.$app.' in appstore</info>');
209 209
 			});
210
-			$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($output) {
211
-				$output->writeln('<info>Update app ' . $app . ' from App Store</info>');
210
+			$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use ($output) {
211
+				$output->writeln('<info>Update app '.$app.' from App Store</info>');
212 212
 			});
213
-			$updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($output) {
214
-				$output->writeln('<info>Checked for update of app "' . $app . '" in App Store </info>');
213
+			$updater->listen('\OC\Updater', 'checkAppStoreApp', function($app) use ($output) {
214
+				$output->writeln('<info>Checked for update of app "'.$app.'" in App Store </info>');
215 215
 			});
216
-			$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($output) {
216
+			$updater->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($output) {
217 217
 				$output->writeln("<info>Checking whether the database schema for <$app> can be updated (this can take a long time depending on the database size)</info>");
218 218
 			});
219
-			$updater->listen('\OC\Updater', 'appUpgradeStarted', function ($app, $version) use ($output) {
219
+			$updater->listen('\OC\Updater', 'appUpgradeStarted', function($app, $version) use ($output) {
220 220
 				$output->writeln("<info>Updating <$app> ...</info>");
221 221
 			});
222
-			$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) {
222
+			$updater->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($output) {
223 223
 				$output->writeln("<info>Updated <$app> to $version</info>");
224 224
 			});
225
-			$updater->listen('\OC\Updater', 'failure', function ($message) use ($output, $self) {
225
+			$updater->listen('\OC\Updater', 'failure', function($message) use ($output, $self) {
226 226
 				$output->writeln("<error>$message</error>");
227 227
 			});
228
-			$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($output) {
228
+			$updater->listen('\OC\Updater', 'setDebugLogLevel', function($logLevel, $logLevelName) use ($output) {
229 229
 				$output->writeln("<info>Setting log level to debug</info>");
230 230
 			});
231
-			$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($output) {
231
+			$updater->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use ($output) {
232 232
 				$output->writeln("<info>Resetting log level</info>");
233 233
 			});
234
-			$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($output) {
234
+			$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use ($output) {
235 235
 				$output->writeln("<info>Starting code integrity check...</info>");
236 236
 			});
237
-			$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($output) {
237
+			$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use ($output) {
238 238
 				$output->writeln("<info>Finished code integrity check</info>");
239 239
 			});
240 240
 
@@ -272,8 +272,8 @@  discard block
 block discarded – undo
272 272
 		$trustedDomains = $this->config->getSystemValue('trusted_domains', []);
273 273
 		if (empty($trustedDomains)) {
274 274
 			$output->write(
275
-				'<warning>The setting "trusted_domains" could not be ' .
276
-				'set automatically by the upgrade script, ' .
275
+				'<warning>The setting "trusted_domains" could not be '.
276
+				'set automatically by the upgrade script, '.
277 277
 				'please set it manually</warning>'
278 278
 			);
279 279
 		}
Please login to merge, or discard this patch.
core/ajax/update.php 2 patches
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
 use Symfony\Component\EventDispatcher\GenericEvent;
37 37
 
38 38
 if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
39
-	@set_time_limit(0);
39
+    @set_time_limit(0);
40 40
 }
41 41
 
42 42
 require_once '../../lib/base.php';
@@ -50,176 +50,176 @@  discard block
 block discarded – undo
50 50
 $eventSource->send('success', $l->t('Preparing update'));
51 51
 
52 52
 class FeedBackHandler {
53
-	/** @var integer */
54
-	private $progressStateMax = 100;
55
-	/** @var integer */
56
-	private $progressStateStep = 0;
57
-	/** @var string */
58
-	private $currentStep;
59
-	/** @var \OCP\IEventSource */
60
-	private $eventSource;
61
-	/** @var \OCP\IL10N */
62
-	private $l10n;
63
-
64
-	public function __construct(\OCP\IEventSource $eventSource, \OCP\IL10N $l10n) {
65
-		$this->eventSource = $eventSource;
66
-		$this->l10n = $l10n;
67
-	}
68
-
69
-	public function handleRepairFeedback($event) {
70
-		if (!$event instanceof GenericEvent) {
71
-			return;
72
-		}
73
-
74
-		switch ($event->getSubject()) {
75
-			case '\OC\Repair::startProgress':
76
-				$this->progressStateMax = $event->getArgument(0);
77
-				$this->progressStateStep = 0;
78
-				$this->currentStep = $event->getArgument(1);
79
-				break;
80
-			case '\OC\Repair::advance':
81
-				$this->progressStateStep += $event->getArgument(0);
82
-				$desc = $event->getArgument(1);
83
-				if (empty($desc)) {
84
-					$desc = $this->currentStep;
85
-				}
86
-				$this->eventSource->send('success', $this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $desc]));
87
-				break;
88
-			case '\OC\Repair::finishProgress':
89
-				$this->progressStateMax = $this->progressStateStep;
90
-				$this->eventSource->send('success', $this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep]));
91
-				break;
92
-			case '\OC\Repair::step':
93
-				$this->eventSource->send('success', $this->l10n->t('Repair step:') . ' ' . $event->getArgument(0));
94
-				break;
95
-			case '\OC\Repair::info':
96
-				$this->eventSource->send('success', $this->l10n->t('Repair info:') . ' ' . $event->getArgument(0));
97
-				break;
98
-			case '\OC\Repair::warning':
99
-				$this->eventSource->send('notice', $this->l10n->t('Repair warning:') . ' ' . $event->getArgument(0));
100
-				break;
101
-			case '\OC\Repair::error':
102
-				$this->eventSource->send('notice', $this->l10n->t('Repair error:') . ' ' . $event->getArgument(0));
103
-				break;
104
-		}
105
-	}
53
+    /** @var integer */
54
+    private $progressStateMax = 100;
55
+    /** @var integer */
56
+    private $progressStateStep = 0;
57
+    /** @var string */
58
+    private $currentStep;
59
+    /** @var \OCP\IEventSource */
60
+    private $eventSource;
61
+    /** @var \OCP\IL10N */
62
+    private $l10n;
63
+
64
+    public function __construct(\OCP\IEventSource $eventSource, \OCP\IL10N $l10n) {
65
+        $this->eventSource = $eventSource;
66
+        $this->l10n = $l10n;
67
+    }
68
+
69
+    public function handleRepairFeedback($event) {
70
+        if (!$event instanceof GenericEvent) {
71
+            return;
72
+        }
73
+
74
+        switch ($event->getSubject()) {
75
+            case '\OC\Repair::startProgress':
76
+                $this->progressStateMax = $event->getArgument(0);
77
+                $this->progressStateStep = 0;
78
+                $this->currentStep = $event->getArgument(1);
79
+                break;
80
+            case '\OC\Repair::advance':
81
+                $this->progressStateStep += $event->getArgument(0);
82
+                $desc = $event->getArgument(1);
83
+                if (empty($desc)) {
84
+                    $desc = $this->currentStep;
85
+                }
86
+                $this->eventSource->send('success', $this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $desc]));
87
+                break;
88
+            case '\OC\Repair::finishProgress':
89
+                $this->progressStateMax = $this->progressStateStep;
90
+                $this->eventSource->send('success', $this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep]));
91
+                break;
92
+            case '\OC\Repair::step':
93
+                $this->eventSource->send('success', $this->l10n->t('Repair step:') . ' ' . $event->getArgument(0));
94
+                break;
95
+            case '\OC\Repair::info':
96
+                $this->eventSource->send('success', $this->l10n->t('Repair info:') . ' ' . $event->getArgument(0));
97
+                break;
98
+            case '\OC\Repair::warning':
99
+                $this->eventSource->send('notice', $this->l10n->t('Repair warning:') . ' ' . $event->getArgument(0));
100
+                break;
101
+            case '\OC\Repair::error':
102
+                $this->eventSource->send('notice', $this->l10n->t('Repair error:') . ' ' . $event->getArgument(0));
103
+                break;
104
+        }
105
+    }
106 106
 }
107 107
 
108 108
 if (\OCP\Util::needUpgrade()) {
109
-	$config = \OC::$server->getSystemConfig();
110
-	if ($config->getValue('upgrade.disable-web', false)) {
111
-		$eventSource->send('failure', $l->t('Please use the command line updater because automatic updating is disabled in the config.php.'));
112
-		$eventSource->close();
113
-		exit();
114
-	}
115
-
116
-	// if a user is currently logged in, their session must be ignored to
117
-	// avoid side effects
118
-	\OC_User::setIncognitoMode(true);
119
-
120
-	$logger = \OC::$server->get(\Psr\Log\LoggerInterface::class);
121
-	$config = \OC::$server->getConfig();
122
-	$updater = new \OC\Updater(
123
-			$config,
124
-			\OC::$server->getIntegrityCodeChecker(),
125
-			$logger,
126
-			\OC::$server->query(\OC\Installer::class)
127
-	);
128
-	$incompatibleApps = [];
129
-
130
-	$dispatcher = \OC::$server->getEventDispatcher();
131
-	$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($eventSource, $l) {
132
-		if ($event instanceof GenericEvent) {
133
-			$eventSource->send('success', $l->t('[%d / %d]: %s', [$event[0], $event[1], $event->getSubject()]));
134
-		}
135
-	});
136
-	$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($eventSource, $l) {
137
-		if ($event instanceof GenericEvent) {
138
-			$eventSource->send('success', $l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()]));
139
-		}
140
-	});
141
-	$feedBack = new FeedBackHandler($eventSource, $l);
142
-	$dispatcher->addListener('\OC\Repair::startProgress', [$feedBack, 'handleRepairFeedback']);
143
-	$dispatcher->addListener('\OC\Repair::advance', [$feedBack, 'handleRepairFeedback']);
144
-	$dispatcher->addListener('\OC\Repair::finishProgress', [$feedBack, 'handleRepairFeedback']);
145
-	$dispatcher->addListener('\OC\Repair::step', [$feedBack, 'handleRepairFeedback']);
146
-	$dispatcher->addListener('\OC\Repair::info', [$feedBack, 'handleRepairFeedback']);
147
-	$dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']);
148
-	$dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']);
149
-
150
-	$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) {
151
-		$eventSource->send('success', $l->t('Turned on maintenance mode'));
152
-	});
153
-	$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) {
154
-		$eventSource->send('success', $l->t('Turned off maintenance mode'));
155
-	});
156
-	$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) {
157
-		$eventSource->send('success', $l->t('Maintenance mode is kept active'));
158
-	});
159
-	$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l) {
160
-		$eventSource->send('success', $l->t('Updating database schema'));
161
-	});
162
-	$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
163
-		$eventSource->send('success', $l->t('Updated database'));
164
-	});
165
-	$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($eventSource, $l) {
166
-		$eventSource->send('success', $l->t('Checking for update of app "%s" in App Store', [$app]));
167
-	});
168
-	$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) {
169
-		$eventSource->send('success', $l->t('Update app "%s" from App Store', [$app]));
170
-	});
171
-	$updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($eventSource, $l) {
172
-		$eventSource->send('success', $l->t('Checked for update of app "%s" in App Store', [$app]));
173
-	});
174
-	$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) {
175
-		$eventSource->send('success', $l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app]));
176
-	});
177
-	$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
178
-		$eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version]));
179
-	});
180
-	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
181
-		$incompatibleApps[] = $app;
182
-	});
183
-	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) {
184
-		$eventSource->send('failure', $message);
185
-		$eventSource->close();
186
-		$config->setSystemValue('maintenance', false);
187
-	});
188
-	$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
189
-		$eventSource->send('success', $l->t('Set log level to debug'));
190
-	});
191
-	$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
192
-		$eventSource->send('success', $l->t('Reset log level'));
193
-	});
194
-	$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l) {
195
-		$eventSource->send('success', $l->t('Starting code integrity check'));
196
-	});
197
-	$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l) {
198
-		$eventSource->send('success', $l->t('Finished code integrity check'));
199
-	});
200
-
201
-	try {
202
-		$updater->upgrade();
203
-	} catch (\Exception $e) {
204
-		\OC::$server->getLogger()->logException($e, [
205
-			'level' => ILogger::ERROR,
206
-			'app' => 'update',
207
-		]);
208
-		$eventSource->send('failure', get_class($e) . ': ' . $e->getMessage());
209
-		$eventSource->close();
210
-		exit();
211
-	}
212
-
213
-	$disabledApps = [];
214
-	foreach ($incompatibleApps as $app) {
215
-		$disabledApps[$app] = $l->t('%s (incompatible)', [$app]);
216
-	}
217
-
218
-	if (!empty($disabledApps)) {
219
-		$eventSource->send('notice', $l->t('The following apps have been disabled: %s', [implode(', ', $disabledApps)]));
220
-	}
109
+    $config = \OC::$server->getSystemConfig();
110
+    if ($config->getValue('upgrade.disable-web', false)) {
111
+        $eventSource->send('failure', $l->t('Please use the command line updater because automatic updating is disabled in the config.php.'));
112
+        $eventSource->close();
113
+        exit();
114
+    }
115
+
116
+    // if a user is currently logged in, their session must be ignored to
117
+    // avoid side effects
118
+    \OC_User::setIncognitoMode(true);
119
+
120
+    $logger = \OC::$server->get(\Psr\Log\LoggerInterface::class);
121
+    $config = \OC::$server->getConfig();
122
+    $updater = new \OC\Updater(
123
+            $config,
124
+            \OC::$server->getIntegrityCodeChecker(),
125
+            $logger,
126
+            \OC::$server->query(\OC\Installer::class)
127
+    );
128
+    $incompatibleApps = [];
129
+
130
+    $dispatcher = \OC::$server->getEventDispatcher();
131
+    $dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($eventSource, $l) {
132
+        if ($event instanceof GenericEvent) {
133
+            $eventSource->send('success', $l->t('[%d / %d]: %s', [$event[0], $event[1], $event->getSubject()]));
134
+        }
135
+    });
136
+    $dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($eventSource, $l) {
137
+        if ($event instanceof GenericEvent) {
138
+            $eventSource->send('success', $l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()]));
139
+        }
140
+    });
141
+    $feedBack = new FeedBackHandler($eventSource, $l);
142
+    $dispatcher->addListener('\OC\Repair::startProgress', [$feedBack, 'handleRepairFeedback']);
143
+    $dispatcher->addListener('\OC\Repair::advance', [$feedBack, 'handleRepairFeedback']);
144
+    $dispatcher->addListener('\OC\Repair::finishProgress', [$feedBack, 'handleRepairFeedback']);
145
+    $dispatcher->addListener('\OC\Repair::step', [$feedBack, 'handleRepairFeedback']);
146
+    $dispatcher->addListener('\OC\Repair::info', [$feedBack, 'handleRepairFeedback']);
147
+    $dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']);
148
+    $dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']);
149
+
150
+    $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) {
151
+        $eventSource->send('success', $l->t('Turned on maintenance mode'));
152
+    });
153
+    $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) {
154
+        $eventSource->send('success', $l->t('Turned off maintenance mode'));
155
+    });
156
+    $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) {
157
+        $eventSource->send('success', $l->t('Maintenance mode is kept active'));
158
+    });
159
+    $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l) {
160
+        $eventSource->send('success', $l->t('Updating database schema'));
161
+    });
162
+    $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
163
+        $eventSource->send('success', $l->t('Updated database'));
164
+    });
165
+    $updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($eventSource, $l) {
166
+        $eventSource->send('success', $l->t('Checking for update of app "%s" in App Store', [$app]));
167
+    });
168
+    $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) {
169
+        $eventSource->send('success', $l->t('Update app "%s" from App Store', [$app]));
170
+    });
171
+    $updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($eventSource, $l) {
172
+        $eventSource->send('success', $l->t('Checked for update of app "%s" in App Store', [$app]));
173
+    });
174
+    $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) {
175
+        $eventSource->send('success', $l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app]));
176
+    });
177
+    $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
178
+        $eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version]));
179
+    });
180
+    $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
181
+        $incompatibleApps[] = $app;
182
+    });
183
+    $updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) {
184
+        $eventSource->send('failure', $message);
185
+        $eventSource->close();
186
+        $config->setSystemValue('maintenance', false);
187
+    });
188
+    $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
189
+        $eventSource->send('success', $l->t('Set log level to debug'));
190
+    });
191
+    $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
192
+        $eventSource->send('success', $l->t('Reset log level'));
193
+    });
194
+    $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l) {
195
+        $eventSource->send('success', $l->t('Starting code integrity check'));
196
+    });
197
+    $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l) {
198
+        $eventSource->send('success', $l->t('Finished code integrity check'));
199
+    });
200
+
201
+    try {
202
+        $updater->upgrade();
203
+    } catch (\Exception $e) {
204
+        \OC::$server->getLogger()->logException($e, [
205
+            'level' => ILogger::ERROR,
206
+            'app' => 'update',
207
+        ]);
208
+        $eventSource->send('failure', get_class($e) . ': ' . $e->getMessage());
209
+        $eventSource->close();
210
+        exit();
211
+    }
212
+
213
+    $disabledApps = [];
214
+    foreach ($incompatibleApps as $app) {
215
+        $disabledApps[$app] = $l->t('%s (incompatible)', [$app]);
216
+    }
217
+
218
+    if (!empty($disabledApps)) {
219
+        $eventSource->send('notice', $l->t('The following apps have been disabled: %s', [implode(', ', $disabledApps)]));
220
+    }
221 221
 } else {
222
-	$eventSource->send('notice', $l->t('Already up to date'));
222
+    $eventSource->send('notice', $l->t('Already up to date'));
223 223
 }
224 224
 
225 225
 $eventSource->send('done', '');
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -90,16 +90,16 @@  discard block
 block discarded – undo
90 90
 				$this->eventSource->send('success', $this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep]));
91 91
 				break;
92 92
 			case '\OC\Repair::step':
93
-				$this->eventSource->send('success', $this->l10n->t('Repair step:') . ' ' . $event->getArgument(0));
93
+				$this->eventSource->send('success', $this->l10n->t('Repair step:').' '.$event->getArgument(0));
94 94
 				break;
95 95
 			case '\OC\Repair::info':
96
-				$this->eventSource->send('success', $this->l10n->t('Repair info:') . ' ' . $event->getArgument(0));
96
+				$this->eventSource->send('success', $this->l10n->t('Repair info:').' '.$event->getArgument(0));
97 97
 				break;
98 98
 			case '\OC\Repair::warning':
99
-				$this->eventSource->send('notice', $this->l10n->t('Repair warning:') . ' ' . $event->getArgument(0));
99
+				$this->eventSource->send('notice', $this->l10n->t('Repair warning:').' '.$event->getArgument(0));
100 100
 				break;
101 101
 			case '\OC\Repair::error':
102
-				$this->eventSource->send('notice', $this->l10n->t('Repair error:') . ' ' . $event->getArgument(0));
102
+				$this->eventSource->send('notice', $this->l10n->t('Repair error:').' '.$event->getArgument(0));
103 103
 				break;
104 104
 		}
105 105
 	}
@@ -128,12 +128,12 @@  discard block
 block discarded – undo
128 128
 	$incompatibleApps = [];
129 129
 
130 130
 	$dispatcher = \OC::$server->getEventDispatcher();
131
-	$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($eventSource, $l) {
131
+	$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($eventSource, $l) {
132 132
 		if ($event instanceof GenericEvent) {
133 133
 			$eventSource->send('success', $l->t('[%d / %d]: %s', [$event[0], $event[1], $event->getSubject()]));
134 134
 		}
135 135
 	});
136
-	$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($eventSource, $l) {
136
+	$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($eventSource, $l) {
137 137
 		if ($event instanceof GenericEvent) {
138 138
 			$eventSource->send('success', $l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()]));
139 139
 		}
@@ -147,54 +147,54 @@  discard block
 block discarded – undo
147 147
 	$dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']);
148 148
 	$dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']);
149 149
 
150
-	$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) {
150
+	$updater->listen('\OC\Updater', 'maintenanceEnabled', function() use ($eventSource, $l) {
151 151
 		$eventSource->send('success', $l->t('Turned on maintenance mode'));
152 152
 	});
153
-	$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) {
153
+	$updater->listen('\OC\Updater', 'maintenanceDisabled', function() use ($eventSource, $l) {
154 154
 		$eventSource->send('success', $l->t('Turned off maintenance mode'));
155 155
 	});
156
-	$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) {
156
+	$updater->listen('\OC\Updater', 'maintenanceActive', function() use ($eventSource, $l) {
157 157
 		$eventSource->send('success', $l->t('Maintenance mode is kept active'));
158 158
 	});
159
-	$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l) {
159
+	$updater->listen('\OC\Updater', 'dbUpgradeBefore', function() use ($eventSource, $l) {
160 160
 		$eventSource->send('success', $l->t('Updating database schema'));
161 161
 	});
162
-	$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
162
+	$updater->listen('\OC\Updater', 'dbUpgrade', function() use ($eventSource, $l) {
163 163
 		$eventSource->send('success', $l->t('Updated database'));
164 164
 	});
165
-	$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($eventSource, $l) {
165
+	$updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use ($eventSource, $l) {
166 166
 		$eventSource->send('success', $l->t('Checking for update of app "%s" in App Store', [$app]));
167 167
 	});
168
-	$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) {
168
+	$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use ($eventSource, $l) {
169 169
 		$eventSource->send('success', $l->t('Update app "%s" from App Store', [$app]));
170 170
 	});
171
-	$updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($eventSource, $l) {
171
+	$updater->listen('\OC\Updater', 'checkAppStoreApp', function($app) use ($eventSource, $l) {
172 172
 		$eventSource->send('success', $l->t('Checked for update of app "%s" in App Store', [$app]));
173 173
 	});
174
-	$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) {
174
+	$updater->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($eventSource, $l) {
175 175
 		$eventSource->send('success', $l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app]));
176 176
 	});
177
-	$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
177
+	$updater->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($eventSource, $l) {
178 178
 		$eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version]));
179 179
 	});
180
-	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
180
+	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use (&$incompatibleApps) {
181 181
 		$incompatibleApps[] = $app;
182 182
 	});
183
-	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) {
183
+	$updater->listen('\OC\Updater', 'failure', function($message) use ($eventSource, $config) {
184 184
 		$eventSource->send('failure', $message);
185 185
 		$eventSource->close();
186 186
 		$config->setSystemValue('maintenance', false);
187 187
 	});
188
-	$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
188
+	$updater->listen('\OC\Updater', 'setDebugLogLevel', function($logLevel, $logLevelName) use ($eventSource, $l) {
189 189
 		$eventSource->send('success', $l->t('Set log level to debug'));
190 190
 	});
191
-	$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) {
191
+	$updater->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use ($eventSource, $l) {
192 192
 		$eventSource->send('success', $l->t('Reset log level'));
193 193
 	});
194
-	$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l) {
194
+	$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use ($eventSource, $l) {
195 195
 		$eventSource->send('success', $l->t('Starting code integrity check'));
196 196
 	});
197
-	$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l) {
197
+	$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use ($eventSource, $l) {
198 198
 		$eventSource->send('success', $l->t('Finished code integrity check'));
199 199
 	});
200 200
 
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 			'level' => ILogger::ERROR,
206 206
 			'app' => 'update',
207 207
 		]);
208
-		$eventSource->send('failure', get_class($e) . ': ' . $e->getMessage());
208
+		$eventSource->send('failure', get_class($e).': '.$e->getMessage());
209 209
 		$eventSource->close();
210 210
 		exit();
211 211
 	}
Please login to merge, or discard this patch.
lib/private/legacy/OC_Util.php 1 patch
Indentation   +1395 added lines, -1395 removed lines patch added patch discarded remove patch
@@ -76,1404 +76,1404 @@
 block discarded – undo
76 76
 use Psr\Log\LoggerInterface;
77 77
 
78 78
 class OC_Util {
79
-	public static $scripts = [];
80
-	public static $styles = [];
81
-	public static $headers = [];
82
-	private static $rootMounted = false;
83
-	private static $fsSetup = false;
84
-
85
-	/** @var array Local cache of version.php */
86
-	private static $versionCache = null;
87
-
88
-	protected static function getAppManager() {
89
-		return \OC::$server->getAppManager();
90
-	}
91
-
92
-	private static function initLocalStorageRootFS() {
93
-		// mount local file backend as root
94
-		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
95
-		//first set up the local "root" storage
96
-		\OC\Files\Filesystem::initMountManager();
97
-		if (!self::$rootMounted) {
98
-			\OC\Files\Filesystem::mount(LocalRootStorage::class, ['datadir' => $configDataDirectory], '/');
99
-			self::$rootMounted = true;
100
-		}
101
-	}
102
-
103
-	/**
104
-	 * mounting an object storage as the root fs will in essence remove the
105
-	 * necessity of a data folder being present.
106
-	 * TODO make home storage aware of this and use the object storage instead of local disk access
107
-	 *
108
-	 * @param array $config containing 'class' and optional 'arguments'
109
-	 * @suppress PhanDeprecatedFunction
110
-	 */
111
-	private static function initObjectStoreRootFS($config) {
112
-		// check misconfiguration
113
-		if (empty($config['class'])) {
114
-			\OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
115
-		}
116
-		if (!isset($config['arguments'])) {
117
-			$config['arguments'] = [];
118
-		}
119
-
120
-		// instantiate object store implementation
121
-		$name = $config['class'];
122
-		if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
123
-			$segments = explode('\\', $name);
124
-			OC_App::loadApp(strtolower($segments[1]));
125
-		}
126
-		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
127
-		// mount with plain / root object store implementation
128
-		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
129
-
130
-		// mount object storage as root
131
-		\OC\Files\Filesystem::initMountManager();
132
-		if (!self::$rootMounted) {
133
-			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
134
-			self::$rootMounted = true;
135
-		}
136
-	}
137
-
138
-	/**
139
-	 * mounting an object storage as the root fs will in essence remove the
140
-	 * necessity of a data folder being present.
141
-	 *
142
-	 * @param array $config containing 'class' and optional 'arguments'
143
-	 * @suppress PhanDeprecatedFunction
144
-	 */
145
-	private static function initObjectStoreMultibucketRootFS($config) {
146
-		// check misconfiguration
147
-		if (empty($config['class'])) {
148
-			\OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
149
-		}
150
-		if (!isset($config['arguments'])) {
151
-			$config['arguments'] = [];
152
-		}
153
-
154
-		// instantiate object store implementation
155
-		$name = $config['class'];
156
-		if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
157
-			$segments = explode('\\', $name);
158
-			OC_App::loadApp(strtolower($segments[1]));
159
-		}
160
-
161
-		if (!isset($config['arguments']['bucket'])) {
162
-			$config['arguments']['bucket'] = '';
163
-		}
164
-		// put the root FS always in first bucket for multibucket configuration
165
-		$config['arguments']['bucket'] .= '0';
166
-
167
-		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
168
-		// mount with plain / root object store implementation
169
-		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
170
-
171
-		// mount object storage as root
172
-		\OC\Files\Filesystem::initMountManager();
173
-		if (!self::$rootMounted) {
174
-			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
175
-			self::$rootMounted = true;
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * Can be set up
181
-	 *
182
-	 * @param string $user
183
-	 * @return boolean
184
-	 * @description configure the initial filesystem based on the configuration
185
-	 * @suppress PhanDeprecatedFunction
186
-	 * @suppress PhanAccessMethodInternal
187
-	 */
188
-	public static function setupFS($user = '') {
189
-		//setting up the filesystem twice can only lead to trouble
190
-		if (self::$fsSetup) {
191
-			return false;
192
-		}
193
-
194
-		\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
195
-
196
-		// If we are not forced to load a specific user we load the one that is logged in
197
-		if ($user === null) {
198
-			$user = '';
199
-		} elseif ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
200
-			$user = OC_User::getUser();
201
-		}
202
-
203
-		// load all filesystem apps before, so no setup-hook gets lost
204
-		OC_App::loadApps(['filesystem']);
205
-
206
-		// the filesystem will finish when $user is not empty,
207
-		// mark fs setup here to avoid doing the setup from loading
208
-		// OC_Filesystem
209
-		if ($user != '') {
210
-			self::$fsSetup = true;
211
-		}
212
-
213
-		\OC\Files\Filesystem::initMountManager();
214
-
215
-		$prevLogging = \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
216
-		\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
217
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
218
-				/** @var \OC\Files\Storage\Common $storage */
219
-				$storage->setMountOptions($mount->getOptions());
220
-			}
221
-			return $storage;
222
-		});
223
-
224
-		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
225
-			if (!$mount->getOption('enable_sharing', true)) {
226
-				return new \OC\Files\Storage\Wrapper\PermissionsMask([
227
-					'storage' => $storage,
228
-					'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
229
-				]);
230
-			}
231
-			return $storage;
232
-		});
233
-
234
-		// install storage availability wrapper, before most other wrappers
235
-		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
236
-			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
237
-				return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
238
-			}
239
-			return $storage;
240
-		});
241
-
242
-		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
243
-			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
244
-				return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
245
-			}
246
-			return $storage;
247
-		});
248
-
249
-		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
250
-			// set up quota for home storages, even for other users
251
-			// which can happen when using sharing
252
-
253
-			/**
254
-			 * @var \OC\Files\Storage\Storage $storage
255
-			 */
256
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
257
-				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
258
-			) {
259
-				/** @var \OC\Files\Storage\Home $storage */
260
-				if (is_object($storage->getUser())) {
261
-					$quota = OC_Util::getUserQuota($storage->getUser());
262
-					if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
263
-						return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
264
-					}
265
-				}
266
-			}
267
-
268
-			return $storage;
269
-		});
270
-
271
-		\OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
272
-			/*
79
+    public static $scripts = [];
80
+    public static $styles = [];
81
+    public static $headers = [];
82
+    private static $rootMounted = false;
83
+    private static $fsSetup = false;
84
+
85
+    /** @var array Local cache of version.php */
86
+    private static $versionCache = null;
87
+
88
+    protected static function getAppManager() {
89
+        return \OC::$server->getAppManager();
90
+    }
91
+
92
+    private static function initLocalStorageRootFS() {
93
+        // mount local file backend as root
94
+        $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
95
+        //first set up the local "root" storage
96
+        \OC\Files\Filesystem::initMountManager();
97
+        if (!self::$rootMounted) {
98
+            \OC\Files\Filesystem::mount(LocalRootStorage::class, ['datadir' => $configDataDirectory], '/');
99
+            self::$rootMounted = true;
100
+        }
101
+    }
102
+
103
+    /**
104
+     * mounting an object storage as the root fs will in essence remove the
105
+     * necessity of a data folder being present.
106
+     * TODO make home storage aware of this and use the object storage instead of local disk access
107
+     *
108
+     * @param array $config containing 'class' and optional 'arguments'
109
+     * @suppress PhanDeprecatedFunction
110
+     */
111
+    private static function initObjectStoreRootFS($config) {
112
+        // check misconfiguration
113
+        if (empty($config['class'])) {
114
+            \OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
115
+        }
116
+        if (!isset($config['arguments'])) {
117
+            $config['arguments'] = [];
118
+        }
119
+
120
+        // instantiate object store implementation
121
+        $name = $config['class'];
122
+        if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
123
+            $segments = explode('\\', $name);
124
+            OC_App::loadApp(strtolower($segments[1]));
125
+        }
126
+        $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
127
+        // mount with plain / root object store implementation
128
+        $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
129
+
130
+        // mount object storage as root
131
+        \OC\Files\Filesystem::initMountManager();
132
+        if (!self::$rootMounted) {
133
+            \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
134
+            self::$rootMounted = true;
135
+        }
136
+    }
137
+
138
+    /**
139
+     * mounting an object storage as the root fs will in essence remove the
140
+     * necessity of a data folder being present.
141
+     *
142
+     * @param array $config containing 'class' and optional 'arguments'
143
+     * @suppress PhanDeprecatedFunction
144
+     */
145
+    private static function initObjectStoreMultibucketRootFS($config) {
146
+        // check misconfiguration
147
+        if (empty($config['class'])) {
148
+            \OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
149
+        }
150
+        if (!isset($config['arguments'])) {
151
+            $config['arguments'] = [];
152
+        }
153
+
154
+        // instantiate object store implementation
155
+        $name = $config['class'];
156
+        if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
157
+            $segments = explode('\\', $name);
158
+            OC_App::loadApp(strtolower($segments[1]));
159
+        }
160
+
161
+        if (!isset($config['arguments']['bucket'])) {
162
+            $config['arguments']['bucket'] = '';
163
+        }
164
+        // put the root FS always in first bucket for multibucket configuration
165
+        $config['arguments']['bucket'] .= '0';
166
+
167
+        $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
168
+        // mount with plain / root object store implementation
169
+        $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
170
+
171
+        // mount object storage as root
172
+        \OC\Files\Filesystem::initMountManager();
173
+        if (!self::$rootMounted) {
174
+            \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
175
+            self::$rootMounted = true;
176
+        }
177
+    }
178
+
179
+    /**
180
+     * Can be set up
181
+     *
182
+     * @param string $user
183
+     * @return boolean
184
+     * @description configure the initial filesystem based on the configuration
185
+     * @suppress PhanDeprecatedFunction
186
+     * @suppress PhanAccessMethodInternal
187
+     */
188
+    public static function setupFS($user = '') {
189
+        //setting up the filesystem twice can only lead to trouble
190
+        if (self::$fsSetup) {
191
+            return false;
192
+        }
193
+
194
+        \OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
195
+
196
+        // If we are not forced to load a specific user we load the one that is logged in
197
+        if ($user === null) {
198
+            $user = '';
199
+        } elseif ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
200
+            $user = OC_User::getUser();
201
+        }
202
+
203
+        // load all filesystem apps before, so no setup-hook gets lost
204
+        OC_App::loadApps(['filesystem']);
205
+
206
+        // the filesystem will finish when $user is not empty,
207
+        // mark fs setup here to avoid doing the setup from loading
208
+        // OC_Filesystem
209
+        if ($user != '') {
210
+            self::$fsSetup = true;
211
+        }
212
+
213
+        \OC\Files\Filesystem::initMountManager();
214
+
215
+        $prevLogging = \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
216
+        \OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
217
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
218
+                /** @var \OC\Files\Storage\Common $storage */
219
+                $storage->setMountOptions($mount->getOptions());
220
+            }
221
+            return $storage;
222
+        });
223
+
224
+        \OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
225
+            if (!$mount->getOption('enable_sharing', true)) {
226
+                return new \OC\Files\Storage\Wrapper\PermissionsMask([
227
+                    'storage' => $storage,
228
+                    'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
229
+                ]);
230
+            }
231
+            return $storage;
232
+        });
233
+
234
+        // install storage availability wrapper, before most other wrappers
235
+        \OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
236
+            if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
237
+                return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
238
+            }
239
+            return $storage;
240
+        });
241
+
242
+        \OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
243
+            if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
244
+                return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
245
+            }
246
+            return $storage;
247
+        });
248
+
249
+        \OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
250
+            // set up quota for home storages, even for other users
251
+            // which can happen when using sharing
252
+
253
+            /**
254
+             * @var \OC\Files\Storage\Storage $storage
255
+             */
256
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
257
+                || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
258
+            ) {
259
+                /** @var \OC\Files\Storage\Home $storage */
260
+                if (is_object($storage->getUser())) {
261
+                    $quota = OC_Util::getUserQuota($storage->getUser());
262
+                    if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
263
+                        return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
264
+                    }
265
+                }
266
+            }
267
+
268
+            return $storage;
269
+        });
270
+
271
+        \OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
272
+            /*
273 273
 			 * Do not allow any operations that modify the storage
274 274
 			 */
275
-			if ($mount->getOption('readonly', false)) {
276
-				return new \OC\Files\Storage\Wrapper\PermissionsMask([
277
-					'storage' => $storage,
278
-					'mask' => \OCP\Constants::PERMISSION_ALL & ~(
279
-						\OCP\Constants::PERMISSION_UPDATE |
280
-						\OCP\Constants::PERMISSION_CREATE |
281
-						\OCP\Constants::PERMISSION_DELETE
282
-					),
283
-				]);
284
-			}
285
-			return $storage;
286
-		});
287
-
288
-		OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user]);
289
-
290
-		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
291
-
292
-		//check if we are using an object storage
293
-		$objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
294
-		$objectStoreMultibucket = \OC::$server->getSystemConfig()->getValue('objectstore_multibucket', null);
295
-
296
-		// use the same order as in ObjectHomeMountProvider
297
-		if (isset($objectStoreMultibucket)) {
298
-			self::initObjectStoreMultibucketRootFS($objectStoreMultibucket);
299
-		} elseif (isset($objectStore)) {
300
-			self::initObjectStoreRootFS($objectStore);
301
-		} else {
302
-			self::initLocalStorageRootFS();
303
-		}
304
-
305
-		/** @var \OCP\Files\Config\IMountProviderCollection $mountProviderCollection */
306
-		$mountProviderCollection = \OC::$server->query(\OCP\Files\Config\IMountProviderCollection::class);
307
-		$rootMountProviders = $mountProviderCollection->getRootMounts();
308
-
309
-		/** @var \OC\Files\Mount\Manager $mountManager */
310
-		$mountManager = \OC\Files\Filesystem::getMountManager();
311
-		foreach ($rootMountProviders as $rootMountProvider) {
312
-			$mountManager->addMount($rootMountProvider);
313
-		}
314
-
315
-		if ($user != '' && !\OC::$server->getUserManager()->userExists($user)) {
316
-			\OC::$server->getEventLogger()->end('setup_fs');
317
-			return false;
318
-		}
319
-
320
-		//if we aren't logged in, there is no use to set up the filesystem
321
-		if ($user != "") {
322
-			$userDir = '/' . $user . '/files';
323
-
324
-			//jail the user into his "home" directory
325
-			\OC\Files\Filesystem::init($user, $userDir);
326
-
327
-			OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user, 'user_dir' => $userDir]);
328
-		}
329
-		\OC::$server->getEventLogger()->end('setup_fs');
330
-		return true;
331
-	}
332
-
333
-	/**
334
-	 * check if a password is required for each public link
335
-	 *
336
-	 * @return boolean
337
-	 * @suppress PhanDeprecatedFunction
338
-	 */
339
-	public static function isPublicLinkPasswordRequired() {
340
-		/** @var IManager $shareManager */
341
-		$shareManager = \OC::$server->get(IManager::class);
342
-		return $shareManager->shareApiLinkEnforcePassword();
343
-	}
344
-
345
-	/**
346
-	 * check if sharing is disabled for the current user
347
-	 * @param IConfig $config
348
-	 * @param IGroupManager $groupManager
349
-	 * @param IUser|null $user
350
-	 * @return bool
351
-	 */
352
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
353
-		/** @var IManager $shareManager */
354
-		$shareManager = \OC::$server->get(IManager::class);
355
-		$userId = $user ? $user->getUID() : null;
356
-		return $shareManager->sharingDisabledForUser($userId);
357
-	}
358
-
359
-	/**
360
-	 * check if share API enforces a default expire date
361
-	 *
362
-	 * @return boolean
363
-	 * @suppress PhanDeprecatedFunction
364
-	 */
365
-	public static function isDefaultExpireDateEnforced() {
366
-		/** @var IManager $shareManager */
367
-		$shareManager = \OC::$server->get(IManager::class);
368
-		return $shareManager->shareApiLinkDefaultExpireDateEnforced();
369
-	}
370
-
371
-	/**
372
-	 * Get the quota of a user
373
-	 *
374
-	 * @param IUser|null $user
375
-	 * @return float Quota bytes
376
-	 */
377
-	public static function getUserQuota(?IUser $user) {
378
-		if (is_null($user)) {
379
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
380
-		}
381
-		$userQuota = $user->getQuota();
382
-		if ($userQuota === 'none') {
383
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
384
-		}
385
-		return OC_Helper::computerFileSize($userQuota);
386
-	}
387
-
388
-	/**
389
-	 * copies the skeleton to the users /files
390
-	 *
391
-	 * @param string $userId
392
-	 * @param \OCP\Files\Folder $userDirectory
393
-	 * @throws \OCP\Files\NotFoundException
394
-	 * @throws \OCP\Files\NotPermittedException
395
-	 * @suppress PhanDeprecatedFunction
396
-	 */
397
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
398
-		/** @var LoggerInterface $logger */
399
-		$logger = \OC::$server->get(LoggerInterface::class);
400
-
401
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
402
-		$userLang = \OC::$server->getL10NFactory()->findLanguage();
403
-		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
404
-
405
-		if (!file_exists($skeletonDirectory)) {
406
-			$dialectStart = strpos($userLang, '_');
407
-			if ($dialectStart !== false) {
408
-				$skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
409
-			}
410
-			if ($dialectStart === false || !file_exists($skeletonDirectory)) {
411
-				$skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
412
-			}
413
-			if (!file_exists($skeletonDirectory)) {
414
-				$skeletonDirectory = '';
415
-			}
416
-		}
417
-
418
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
419
-
420
-		if ($instanceId === null) {
421
-			throw new \RuntimeException('no instance id!');
422
-		}
423
-		$appdata = 'appdata_' . $instanceId;
424
-		if ($userId === $appdata) {
425
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
426
-		}
427
-
428
-		if (!empty($skeletonDirectory)) {
429
-			$logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
430
-			self::copyr($skeletonDirectory, $userDirectory);
431
-			// update the file cache
432
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
433
-
434
-			/** @var ITemplateManager $templateManager */
435
-			$templateManager = \OC::$server->get(ITemplateManager::class);
436
-			$templateManager->initializeTemplateDirectory(null, $userId);
437
-		}
438
-	}
439
-
440
-	/**
441
-	 * copies a directory recursively by using streams
442
-	 *
443
-	 * @param string $source
444
-	 * @param \OCP\Files\Folder $target
445
-	 * @return void
446
-	 */
447
-	public static function copyr($source, \OCP\Files\Folder $target) {
448
-		$logger = \OC::$server->getLogger();
449
-
450
-		// Verify if folder exists
451
-		$dir = opendir($source);
452
-		if ($dir === false) {
453
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
454
-			return;
455
-		}
456
-
457
-		// Copy the files
458
-		while (false !== ($file = readdir($dir))) {
459
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
460
-				if (is_dir($source . '/' . $file)) {
461
-					$child = $target->newFolder($file);
462
-					self::copyr($source . '/' . $file, $child);
463
-				} else {
464
-					$child = $target->newFile($file);
465
-					$sourceStream = fopen($source . '/' . $file, 'r');
466
-					if ($sourceStream === false) {
467
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
468
-						closedir($dir);
469
-						return;
470
-					}
471
-					stream_copy_to_stream($sourceStream, $child->fopen('w'));
472
-				}
473
-			}
474
-		}
475
-		closedir($dir);
476
-	}
477
-
478
-	/**
479
-	 * @return void
480
-	 * @suppress PhanUndeclaredMethod
481
-	 */
482
-	public static function tearDownFS() {
483
-		\OC\Files\Filesystem::tearDown();
484
-		\OC::$server->getRootFolder()->clearCache();
485
-		self::$fsSetup = false;
486
-		self::$rootMounted = false;
487
-	}
488
-
489
-	/**
490
-	 * get the current installed version of ownCloud
491
-	 *
492
-	 * @return array
493
-	 */
494
-	public static function getVersion() {
495
-		OC_Util::loadVersion();
496
-		return self::$versionCache['OC_Version'];
497
-	}
498
-
499
-	/**
500
-	 * get the current installed version string of ownCloud
501
-	 *
502
-	 * @return string
503
-	 */
504
-	public static function getVersionString() {
505
-		OC_Util::loadVersion();
506
-		return self::$versionCache['OC_VersionString'];
507
-	}
508
-
509
-	/**
510
-	 * @deprecated the value is of no use anymore
511
-	 * @return string
512
-	 */
513
-	public static function getEditionString() {
514
-		return '';
515
-	}
516
-
517
-	/**
518
-	 * @description get the update channel of the current installed of ownCloud.
519
-	 * @return string
520
-	 */
521
-	public static function getChannel() {
522
-		OC_Util::loadVersion();
523
-		return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
524
-	}
525
-
526
-	/**
527
-	 * @description get the build number of the current installed of ownCloud.
528
-	 * @return string
529
-	 */
530
-	public static function getBuild() {
531
-		OC_Util::loadVersion();
532
-		return self::$versionCache['OC_Build'];
533
-	}
534
-
535
-	/**
536
-	 * @description load the version.php into the session as cache
537
-	 * @suppress PhanUndeclaredVariable
538
-	 */
539
-	private static function loadVersion() {
540
-		if (self::$versionCache !== null) {
541
-			return;
542
-		}
543
-
544
-		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
545
-		require OC::$SERVERROOT . '/version.php';
546
-		/** @var int $timestamp */
547
-		self::$versionCache['OC_Version_Timestamp'] = $timestamp;
548
-		/** @var string $OC_Version */
549
-		self::$versionCache['OC_Version'] = $OC_Version;
550
-		/** @var string $OC_VersionString */
551
-		self::$versionCache['OC_VersionString'] = $OC_VersionString;
552
-		/** @var string $OC_Build */
553
-		self::$versionCache['OC_Build'] = $OC_Build;
554
-
555
-		/** @var string $OC_Channel */
556
-		self::$versionCache['OC_Channel'] = $OC_Channel;
557
-	}
558
-
559
-	/**
560
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
561
-	 *
562
-	 * @param string $application application to get the files from
563
-	 * @param string $directory directory within this application (css, js, vendor, etc)
564
-	 * @param string $file the file inside of the above folder
565
-	 * @return string the path
566
-	 */
567
-	private static function generatePath($application, $directory, $file) {
568
-		if (is_null($file)) {
569
-			$file = $application;
570
-			$application = "";
571
-		}
572
-		if (!empty($application)) {
573
-			return "$application/$directory/$file";
574
-		} else {
575
-			return "$directory/$file";
576
-		}
577
-	}
578
-
579
-	/**
580
-	 * add a javascript file
581
-	 *
582
-	 * @param string $application application id
583
-	 * @param string|null $file filename
584
-	 * @param bool $prepend prepend the Script to the beginning of the list
585
-	 * @return void
586
-	 */
587
-	public static function addScript($application, $file = null, $prepend = false) {
588
-		$path = OC_Util::generatePath($application, 'js', $file);
589
-
590
-		// core js files need separate handling
591
-		if ($application !== 'core' && $file !== null) {
592
-			self::addTranslations($application);
593
-		}
594
-		self::addExternalResource($application, $prepend, $path, "script");
595
-	}
596
-
597
-	/**
598
-	 * add a javascript file from the vendor sub folder
599
-	 *
600
-	 * @param string $application application id
601
-	 * @param string|null $file filename
602
-	 * @param bool $prepend prepend the Script to the beginning of the list
603
-	 * @return void
604
-	 */
605
-	public static function addVendorScript($application, $file = null, $prepend = false) {
606
-		$path = OC_Util::generatePath($application, 'vendor', $file);
607
-		self::addExternalResource($application, $prepend, $path, "script");
608
-	}
609
-
610
-	/**
611
-	 * add a translation JS file
612
-	 *
613
-	 * @param string $application application id
614
-	 * @param string|null $languageCode language code, defaults to the current language
615
-	 * @param bool|null $prepend prepend the Script to the beginning of the list
616
-	 */
617
-	public static function addTranslations($application, $languageCode = null, $prepend = false) {
618
-		if (is_null($languageCode)) {
619
-			$languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
620
-		}
621
-		if (!empty($application)) {
622
-			$path = "$application/l10n/$languageCode";
623
-		} else {
624
-			$path = "l10n/$languageCode";
625
-		}
626
-		self::addExternalResource($application, $prepend, $path, "script");
627
-	}
628
-
629
-	/**
630
-	 * add a css file
631
-	 *
632
-	 * @param string $application application id
633
-	 * @param string|null $file filename
634
-	 * @param bool $prepend prepend the Style to the beginning of the list
635
-	 * @return void
636
-	 */
637
-	public static function addStyle($application, $file = null, $prepend = false) {
638
-		$path = OC_Util::generatePath($application, 'css', $file);
639
-		self::addExternalResource($application, $prepend, $path, "style");
640
-	}
641
-
642
-	/**
643
-	 * add a css file from the vendor sub folder
644
-	 *
645
-	 * @param string $application application id
646
-	 * @param string|null $file filename
647
-	 * @param bool $prepend prepend the Style to the beginning of the list
648
-	 * @return void
649
-	 */
650
-	public static function addVendorStyle($application, $file = null, $prepend = false) {
651
-		$path = OC_Util::generatePath($application, 'vendor', $file);
652
-		self::addExternalResource($application, $prepend, $path, "style");
653
-	}
654
-
655
-	/**
656
-	 * add an external resource css/js file
657
-	 *
658
-	 * @param string $application application id
659
-	 * @param bool $prepend prepend the file to the beginning of the list
660
-	 * @param string $path
661
-	 * @param string $type (script or style)
662
-	 * @return void
663
-	 */
664
-	private static function addExternalResource($application, $prepend, $path, $type = "script") {
665
-		if ($type === "style") {
666
-			if (!in_array($path, self::$styles)) {
667
-				if ($prepend === true) {
668
-					array_unshift(self::$styles, $path);
669
-				} else {
670
-					self::$styles[] = $path;
671
-				}
672
-			}
673
-		} elseif ($type === "script") {
674
-			if (!in_array($path, self::$scripts)) {
675
-				if ($prepend === true) {
676
-					array_unshift(self::$scripts, $path);
677
-				} else {
678
-					self::$scripts [] = $path;
679
-				}
680
-			}
681
-		}
682
-	}
683
-
684
-	/**
685
-	 * Add a custom element to the header
686
-	 * If $text is null then the element will be written as empty element.
687
-	 * So use "" to get a closing tag.
688
-	 * @param string $tag tag name of the element
689
-	 * @param array $attributes array of attributes for the element
690
-	 * @param string $text the text content for the element
691
-	 * @param bool $prepend prepend the header to the beginning of the list
692
-	 */
693
-	public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
694
-		$header = [
695
-			'tag' => $tag,
696
-			'attributes' => $attributes,
697
-			'text' => $text
698
-		];
699
-		if ($prepend === true) {
700
-			array_unshift(self::$headers, $header);
701
-		} else {
702
-			self::$headers[] = $header;
703
-		}
704
-	}
705
-
706
-	/**
707
-	 * check if the current server configuration is suitable for ownCloud
708
-	 *
709
-	 * @param \OC\SystemConfig $config
710
-	 * @return array arrays with error messages and hints
711
-	 */
712
-	public static function checkServer(\OC\SystemConfig $config) {
713
-		$l = \OC::$server->getL10N('lib');
714
-		$errors = [];
715
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
716
-
717
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
718
-			// this check needs to be done every time
719
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
720
-		}
721
-
722
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
723
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
724
-			return $errors;
725
-		}
726
-
727
-		$webServerRestart = false;
728
-		$setup = new \OC\Setup(
729
-			$config,
730
-			\OC::$server->get(IniGetWrapper::class),
731
-			\OC::$server->getL10N('lib'),
732
-			\OC::$server->get(\OCP\Defaults::class),
733
-			\OC::$server->get(LoggerInterface::class),
734
-			\OC::$server->getSecureRandom(),
735
-			\OC::$server->get(\OC\Installer::class)
736
-		);
737
-
738
-		$urlGenerator = \OC::$server->getURLGenerator();
739
-
740
-		$availableDatabases = $setup->getSupportedDatabases();
741
-		if (empty($availableDatabases)) {
742
-			$errors[] = [
743
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
744
-				'hint' => '' //TODO: sane hint
745
-			];
746
-			$webServerRestart = true;
747
-		}
748
-
749
-		// Check if config folder is writable.
750
-		if (!OC_Helper::isReadOnlyConfigEnabled()) {
751
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
752
-				$errors[] = [
753
-					'error' => $l->t('Cannot write into "config" directory'),
754
-					'hint' => $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
755
-						[ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
756
-						. $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',
757
-						[ $urlGenerator->linkToDocs('admin-config') ])
758
-				];
759
-			}
760
-		}
761
-
762
-		// Check if there is a writable install folder.
763
-		if ($config->getValue('appstoreenabled', true)) {
764
-			if (OC_App::getInstallPath() === null
765
-				|| !is_writable(OC_App::getInstallPath())
766
-				|| !is_readable(OC_App::getInstallPath())
767
-			) {
768
-				$errors[] = [
769
-					'error' => $l->t('Cannot write into "apps" directory'),
770
-					'hint' => $l->t('This can usually be fixed by giving the webserver write access to the apps directory'
771
-						. ' or disabling the App Store in the config file.')
772
-				];
773
-			}
774
-		}
775
-		// Create root dir.
776
-		if ($config->getValue('installed', false)) {
777
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
778
-				$success = @mkdir($CONFIG_DATADIRECTORY);
779
-				if ($success) {
780
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
781
-				} else {
782
-					$errors[] = [
783
-						'error' => $l->t('Cannot create "data" directory'),
784
-						'hint' => $l->t('This can usually be fixed by giving the webserver write access to the root directory. See %s',
785
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
786
-					];
787
-				}
788
-			} elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
789
-				// is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
790
-				$testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
791
-				$handle = fopen($testFile, 'w');
792
-				if (!$handle || fwrite($handle, 'Test write operation') === false) {
793
-					$permissionsHint = $l->t('Permissions can usually be fixed by giving the webserver write access to the root directory. See %s.',
794
-						[$urlGenerator->linkToDocs('admin-dir_permissions')]);
795
-					$errors[] = [
796
-						'error' => 'Your data directory is not writable',
797
-						'hint' => $permissionsHint
798
-					];
799
-				} else {
800
-					fclose($handle);
801
-					unlink($testFile);
802
-				}
803
-			} else {
804
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
805
-			}
806
-		}
807
-
808
-		if (!OC_Util::isSetLocaleWorking()) {
809
-			$errors[] = [
810
-				'error' => $l->t('Setting locale to %s failed',
811
-					['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
812
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
813
-				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
814
-			];
815
-		}
816
-
817
-		// Contains the dependencies that should be checked against
818
-		// classes = class_exists
819
-		// functions = function_exists
820
-		// defined = defined
821
-		// ini = ini_get
822
-		// If the dependency is not found the missing module name is shown to the EndUser
823
-		// When adding new checks always verify that they pass on Travis as well
824
-		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
825
-		$dependencies = [
826
-			'classes' => [
827
-				'ZipArchive' => 'zip',
828
-				'DOMDocument' => 'dom',
829
-				'XMLWriter' => 'XMLWriter',
830
-				'XMLReader' => 'XMLReader',
831
-			],
832
-			'functions' => [
833
-				'xml_parser_create' => 'libxml',
834
-				'mb_strcut' => 'mbstring',
835
-				'ctype_digit' => 'ctype',
836
-				'json_encode' => 'JSON',
837
-				'gd_info' => 'GD',
838
-				'gzencode' => 'zlib',
839
-				'iconv' => 'iconv',
840
-				'simplexml_load_string' => 'SimpleXML',
841
-				'hash' => 'HASH Message Digest Framework',
842
-				'curl_init' => 'cURL',
843
-				'openssl_verify' => 'OpenSSL',
844
-			],
845
-			'defined' => [
846
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
847
-			],
848
-			'ini' => [
849
-				'default_charset' => 'UTF-8',
850
-			],
851
-		];
852
-		$missingDependencies = [];
853
-		$invalidIniSettings = [];
854
-
855
-		$iniWrapper = \OC::$server->get(IniGetWrapper::class);
856
-		foreach ($dependencies['classes'] as $class => $module) {
857
-			if (!class_exists($class)) {
858
-				$missingDependencies[] = $module;
859
-			}
860
-		}
861
-		foreach ($dependencies['functions'] as $function => $module) {
862
-			if (!function_exists($function)) {
863
-				$missingDependencies[] = $module;
864
-			}
865
-		}
866
-		foreach ($dependencies['defined'] as $defined => $module) {
867
-			if (!defined($defined)) {
868
-				$missingDependencies[] = $module;
869
-			}
870
-		}
871
-		foreach ($dependencies['ini'] as $setting => $expected) {
872
-			if (is_bool($expected)) {
873
-				if ($iniWrapper->getBool($setting) !== $expected) {
874
-					$invalidIniSettings[] = [$setting, $expected];
875
-				}
876
-			}
877
-			if (is_int($expected)) {
878
-				if ($iniWrapper->getNumeric($setting) !== $expected) {
879
-					$invalidIniSettings[] = [$setting, $expected];
880
-				}
881
-			}
882
-			if (is_string($expected)) {
883
-				if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
884
-					$invalidIniSettings[] = [$setting, $expected];
885
-				}
886
-			}
887
-		}
888
-
889
-		foreach ($missingDependencies as $missingDependency) {
890
-			$errors[] = [
891
-				'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
892
-				'hint' => $l->t('Please ask your server administrator to install the module.'),
893
-			];
894
-			$webServerRestart = true;
895
-		}
896
-		foreach ($invalidIniSettings as $setting) {
897
-			if (is_bool($setting[1])) {
898
-				$setting[1] = $setting[1] ? 'on' : 'off';
899
-			}
900
-			$errors[] = [
901
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
902
-				'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
903
-			];
904
-			$webServerRestart = true;
905
-		}
906
-
907
-		/**
908
-		 * The mbstring.func_overload check can only be performed if the mbstring
909
-		 * module is installed as it will return null if the checking setting is
910
-		 * not available and thus a check on the boolean value fails.
911
-		 *
912
-		 * TODO: Should probably be implemented in the above generic dependency
913
-		 *       check somehow in the long-term.
914
-		 */
915
-		if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
916
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
917
-			$errors[] = [
918
-				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
919
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
920
-			];
921
-		}
922
-
923
-		if (function_exists('xml_parser_create') &&
924
-			LIBXML_LOADED_VERSION < 20700) {
925
-			$version = LIBXML_LOADED_VERSION;
926
-			$major = floor($version / 10000);
927
-			$version -= ($major * 10000);
928
-			$minor = floor($version / 100);
929
-			$version -= ($minor * 100);
930
-			$patch = $version;
931
-			$errors[] = [
932
-				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
933
-				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
934
-			];
935
-		}
936
-
937
-		if (!self::isAnnotationsWorking()) {
938
-			$errors[] = [
939
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
940
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
941
-			];
942
-		}
943
-
944
-		if (!\OC::$CLI && $webServerRestart) {
945
-			$errors[] = [
946
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
947
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
948
-			];
949
-		}
950
-
951
-		$errors = array_merge($errors, self::checkDatabaseVersion());
952
-
953
-		// Cache the result of this function
954
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
955
-
956
-		return $errors;
957
-	}
958
-
959
-	/**
960
-	 * Check the database version
961
-	 *
962
-	 * @return array errors array
963
-	 */
964
-	public static function checkDatabaseVersion() {
965
-		$l = \OC::$server->getL10N('lib');
966
-		$errors = [];
967
-		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
968
-		if ($dbType === 'pgsql') {
969
-			// check PostgreSQL version
970
-			try {
971
-				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
972
-				$data = $result->fetchRow();
973
-				$result->closeCursor();
974
-				if (isset($data['server_version'])) {
975
-					$version = $data['server_version'];
976
-					if (version_compare($version, '9.0.0', '<')) {
977
-						$errors[] = [
978
-							'error' => $l->t('PostgreSQL >= 9 required'),
979
-							'hint' => $l->t('Please upgrade your database version')
980
-						];
981
-					}
982
-				}
983
-			} catch (\Doctrine\DBAL\Exception $e) {
984
-				$logger = \OC::$server->getLogger();
985
-				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
986
-				$logger->logException($e);
987
-			}
988
-		}
989
-		return $errors;
990
-	}
991
-
992
-	/**
993
-	 * Check for correct file permissions of data directory
994
-	 *
995
-	 * @param string $dataDirectory
996
-	 * @return array arrays with error messages and hints
997
-	 */
998
-	public static function checkDataDirectoryPermissions($dataDirectory) {
999
-		if (\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
1000
-			return  [];
1001
-		}
1002
-
1003
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
1004
-		if (substr($perms, -1) !== '0') {
1005
-			chmod($dataDirectory, 0770);
1006
-			clearstatcache();
1007
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
1008
-			if ($perms[2] !== '0') {
1009
-				$l = \OC::$server->getL10N('lib');
1010
-				return [[
1011
-					'error' => $l->t('Your data directory is readable by other users'),
1012
-					'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'),
1013
-				]];
1014
-			}
1015
-		}
1016
-		return [];
1017
-	}
1018
-
1019
-	/**
1020
-	 * Check that the data directory exists and is valid by
1021
-	 * checking the existence of the ".ocdata" file.
1022
-	 *
1023
-	 * @param string $dataDirectory data directory path
1024
-	 * @return array errors found
1025
-	 */
1026
-	public static function checkDataDirectoryValidity($dataDirectory) {
1027
-		$l = \OC::$server->getL10N('lib');
1028
-		$errors = [];
1029
-		if ($dataDirectory[0] !== '/') {
1030
-			$errors[] = [
1031
-				'error' => $l->t('Your data directory must be an absolute path'),
1032
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
1033
-			];
1034
-		}
1035
-		if (!file_exists($dataDirectory . '/.ocdata')) {
1036
-			$errors[] = [
1037
-				'error' => $l->t('Your data directory is invalid'),
1038
-				'hint' => $l->t('Ensure there is a file called ".ocdata"' .
1039
-					' in the root of the data directory.')
1040
-			];
1041
-		}
1042
-		return $errors;
1043
-	}
1044
-
1045
-	/**
1046
-	 * Check if the user is logged in, redirects to home if not. With
1047
-	 * redirect URL parameter to the request URI.
1048
-	 *
1049
-	 * @return void
1050
-	 */
1051
-	public static function checkLoggedIn() {
1052
-		// Check if we are a user
1053
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
1054
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
1055
-						'core.login.showLoginForm',
1056
-						[
1057
-							'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
1058
-						]
1059
-					)
1060
-			);
1061
-			exit();
1062
-		}
1063
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
1064
-		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
1065
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
1066
-			exit();
1067
-		}
1068
-	}
1069
-
1070
-	/**
1071
-	 * Check if the user is a admin, redirects to home if not
1072
-	 *
1073
-	 * @return void
1074
-	 */
1075
-	public static function checkAdminUser() {
1076
-		OC_Util::checkLoggedIn();
1077
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
1078
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1079
-			exit();
1080
-		}
1081
-	}
1082
-
1083
-	/**
1084
-	 * Returns the URL of the default page
1085
-	 * based on the system configuration and
1086
-	 * the apps visible for the current user
1087
-	 *
1088
-	 * @return string URL
1089
-	 * @suppress PhanDeprecatedFunction
1090
-	 */
1091
-	public static function getDefaultPageUrl() {
1092
-		/** @var IConfig $config */
1093
-		$config = \OC::$server->get(IConfig::class);
1094
-		$urlGenerator = \OC::$server->getURLGenerator();
1095
-		// Deny the redirect if the URL contains a @
1096
-		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
1097
-		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1098
-			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1099
-		} else {
1100
-			$defaultPage = \OC::$server->getConfig()->getAppValue('core', 'defaultpage');
1101
-			if ($defaultPage) {
1102
-				$location = $urlGenerator->getAbsoluteURL($defaultPage);
1103
-			} else {
1104
-				$appId = 'files';
1105
-				$defaultApps = explode(',', $config->getSystemValue('defaultapp', 'dashboard,files'));
1106
-
1107
-				/** @var IUserSession $userSession */
1108
-				$userSession = \OC::$server->get(IUserSession::class);
1109
-				$user = $userSession->getUser();
1110
-				if ($user) {
1111
-					$userDefaultApps = explode(',', $config->getUserValue($user->getUID(), 'core', 'defaultapp'));
1112
-					$defaultApps = array_filter(array_merge($userDefaultApps, $defaultApps));
1113
-				}
1114
-
1115
-				// find the first app that is enabled for the current user
1116
-				foreach ($defaultApps as $defaultApp) {
1117
-					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1118
-					if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1119
-						$appId = $defaultApp;
1120
-						break;
1121
-					}
1122
-				}
1123
-
1124
-				if ($config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1125
-					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1126
-				} else {
1127
-					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1128
-				}
1129
-			}
1130
-		}
1131
-		return $location;
1132
-	}
1133
-
1134
-	/**
1135
-	 * Redirect to the user default page
1136
-	 *
1137
-	 * @return void
1138
-	 */
1139
-	public static function redirectToDefaultPage() {
1140
-		$location = self::getDefaultPageUrl();
1141
-		header('Location: ' . $location);
1142
-		exit();
1143
-	}
1144
-
1145
-	/**
1146
-	 * get an id unique for this instance
1147
-	 *
1148
-	 * @return string
1149
-	 */
1150
-	public static function getInstanceId() {
1151
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1152
-		if (is_null($id)) {
1153
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1154
-			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1155
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1156
-		}
1157
-		return $id;
1158
-	}
1159
-
1160
-	/**
1161
-	 * Public function to sanitize HTML
1162
-	 *
1163
-	 * This function is used to sanitize HTML and should be applied on any
1164
-	 * string or array of strings before displaying it on a web page.
1165
-	 *
1166
-	 * @param string|array $value
1167
-	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1168
-	 */
1169
-	public static function sanitizeHTML($value) {
1170
-		if (is_array($value)) {
1171
-			$value = array_map(function ($value) {
1172
-				return self::sanitizeHTML($value);
1173
-			}, $value);
1174
-		} else {
1175
-			// Specify encoding for PHP<5.4
1176
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1177
-		}
1178
-		return $value;
1179
-	}
1180
-
1181
-	/**
1182
-	 * Public function to encode url parameters
1183
-	 *
1184
-	 * This function is used to encode path to file before output.
1185
-	 * Encoding is done according to RFC 3986 with one exception:
1186
-	 * Character '/' is preserved as is.
1187
-	 *
1188
-	 * @param string $component part of URI to encode
1189
-	 * @return string
1190
-	 */
1191
-	public static function encodePath($component) {
1192
-		$encoded = rawurlencode($component);
1193
-		$encoded = str_replace('%2F', '/', $encoded);
1194
-		return $encoded;
1195
-	}
1196
-
1197
-
1198
-	public function createHtaccessTestFile(\OCP\IConfig $config) {
1199
-		// php dev server does not support htaccess
1200
-		if (php_sapi_name() === 'cli-server') {
1201
-			return false;
1202
-		}
1203
-
1204
-		// testdata
1205
-		$fileName = '/htaccesstest.txt';
1206
-		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1207
-
1208
-		// creating a test file
1209
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1210
-
1211
-		if (file_exists($testFile)) {// already running this test, possible recursive call
1212
-			return false;
1213
-		}
1214
-
1215
-		$fp = @fopen($testFile, 'w');
1216
-		if (!$fp) {
1217
-			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1218
-				'Make sure it is possible for the webserver to write to ' . $testFile);
1219
-		}
1220
-		fwrite($fp, $testContent);
1221
-		fclose($fp);
1222
-
1223
-		return $testContent;
1224
-	}
1225
-
1226
-	/**
1227
-	 * Check if the .htaccess file is working
1228
-	 * @param \OCP\IConfig $config
1229
-	 * @return bool
1230
-	 * @throws Exception
1231
-	 * @throws \OC\HintException If the test file can't get written.
1232
-	 */
1233
-	public function isHtaccessWorking(\OCP\IConfig $config) {
1234
-		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1235
-			return true;
1236
-		}
1237
-
1238
-		$testContent = $this->createHtaccessTestFile($config);
1239
-		if ($testContent === false) {
1240
-			return false;
1241
-		}
1242
-
1243
-		$fileName = '/htaccesstest.txt';
1244
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1245
-
1246
-		// accessing the file via http
1247
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1248
-		try {
1249
-			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1250
-		} catch (\Exception $e) {
1251
-			$content = false;
1252
-		}
1253
-
1254
-		if (strpos($url, 'https:') === 0) {
1255
-			$url = 'http:' . substr($url, 6);
1256
-		} else {
1257
-			$url = 'https:' . substr($url, 5);
1258
-		}
1259
-
1260
-		try {
1261
-			$fallbackContent = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1262
-		} catch (\Exception $e) {
1263
-			$fallbackContent = false;
1264
-		}
1265
-
1266
-		// cleanup
1267
-		@unlink($testFile);
1268
-
1269
-		/*
275
+            if ($mount->getOption('readonly', false)) {
276
+                return new \OC\Files\Storage\Wrapper\PermissionsMask([
277
+                    'storage' => $storage,
278
+                    'mask' => \OCP\Constants::PERMISSION_ALL & ~(
279
+                        \OCP\Constants::PERMISSION_UPDATE |
280
+                        \OCP\Constants::PERMISSION_CREATE |
281
+                        \OCP\Constants::PERMISSION_DELETE
282
+                    ),
283
+                ]);
284
+            }
285
+            return $storage;
286
+        });
287
+
288
+        OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user]);
289
+
290
+        \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
291
+
292
+        //check if we are using an object storage
293
+        $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
294
+        $objectStoreMultibucket = \OC::$server->getSystemConfig()->getValue('objectstore_multibucket', null);
295
+
296
+        // use the same order as in ObjectHomeMountProvider
297
+        if (isset($objectStoreMultibucket)) {
298
+            self::initObjectStoreMultibucketRootFS($objectStoreMultibucket);
299
+        } elseif (isset($objectStore)) {
300
+            self::initObjectStoreRootFS($objectStore);
301
+        } else {
302
+            self::initLocalStorageRootFS();
303
+        }
304
+
305
+        /** @var \OCP\Files\Config\IMountProviderCollection $mountProviderCollection */
306
+        $mountProviderCollection = \OC::$server->query(\OCP\Files\Config\IMountProviderCollection::class);
307
+        $rootMountProviders = $mountProviderCollection->getRootMounts();
308
+
309
+        /** @var \OC\Files\Mount\Manager $mountManager */
310
+        $mountManager = \OC\Files\Filesystem::getMountManager();
311
+        foreach ($rootMountProviders as $rootMountProvider) {
312
+            $mountManager->addMount($rootMountProvider);
313
+        }
314
+
315
+        if ($user != '' && !\OC::$server->getUserManager()->userExists($user)) {
316
+            \OC::$server->getEventLogger()->end('setup_fs');
317
+            return false;
318
+        }
319
+
320
+        //if we aren't logged in, there is no use to set up the filesystem
321
+        if ($user != "") {
322
+            $userDir = '/' . $user . '/files';
323
+
324
+            //jail the user into his "home" directory
325
+            \OC\Files\Filesystem::init($user, $userDir);
326
+
327
+            OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user, 'user_dir' => $userDir]);
328
+        }
329
+        \OC::$server->getEventLogger()->end('setup_fs');
330
+        return true;
331
+    }
332
+
333
+    /**
334
+     * check if a password is required for each public link
335
+     *
336
+     * @return boolean
337
+     * @suppress PhanDeprecatedFunction
338
+     */
339
+    public static function isPublicLinkPasswordRequired() {
340
+        /** @var IManager $shareManager */
341
+        $shareManager = \OC::$server->get(IManager::class);
342
+        return $shareManager->shareApiLinkEnforcePassword();
343
+    }
344
+
345
+    /**
346
+     * check if sharing is disabled for the current user
347
+     * @param IConfig $config
348
+     * @param IGroupManager $groupManager
349
+     * @param IUser|null $user
350
+     * @return bool
351
+     */
352
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
353
+        /** @var IManager $shareManager */
354
+        $shareManager = \OC::$server->get(IManager::class);
355
+        $userId = $user ? $user->getUID() : null;
356
+        return $shareManager->sharingDisabledForUser($userId);
357
+    }
358
+
359
+    /**
360
+     * check if share API enforces a default expire date
361
+     *
362
+     * @return boolean
363
+     * @suppress PhanDeprecatedFunction
364
+     */
365
+    public static function isDefaultExpireDateEnforced() {
366
+        /** @var IManager $shareManager */
367
+        $shareManager = \OC::$server->get(IManager::class);
368
+        return $shareManager->shareApiLinkDefaultExpireDateEnforced();
369
+    }
370
+
371
+    /**
372
+     * Get the quota of a user
373
+     *
374
+     * @param IUser|null $user
375
+     * @return float Quota bytes
376
+     */
377
+    public static function getUserQuota(?IUser $user) {
378
+        if (is_null($user)) {
379
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
380
+        }
381
+        $userQuota = $user->getQuota();
382
+        if ($userQuota === 'none') {
383
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
384
+        }
385
+        return OC_Helper::computerFileSize($userQuota);
386
+    }
387
+
388
+    /**
389
+     * copies the skeleton to the users /files
390
+     *
391
+     * @param string $userId
392
+     * @param \OCP\Files\Folder $userDirectory
393
+     * @throws \OCP\Files\NotFoundException
394
+     * @throws \OCP\Files\NotPermittedException
395
+     * @suppress PhanDeprecatedFunction
396
+     */
397
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
398
+        /** @var LoggerInterface $logger */
399
+        $logger = \OC::$server->get(LoggerInterface::class);
400
+
401
+        $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
402
+        $userLang = \OC::$server->getL10NFactory()->findLanguage();
403
+        $skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
404
+
405
+        if (!file_exists($skeletonDirectory)) {
406
+            $dialectStart = strpos($userLang, '_');
407
+            if ($dialectStart !== false) {
408
+                $skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
409
+            }
410
+            if ($dialectStart === false || !file_exists($skeletonDirectory)) {
411
+                $skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
412
+            }
413
+            if (!file_exists($skeletonDirectory)) {
414
+                $skeletonDirectory = '';
415
+            }
416
+        }
417
+
418
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
419
+
420
+        if ($instanceId === null) {
421
+            throw new \RuntimeException('no instance id!');
422
+        }
423
+        $appdata = 'appdata_' . $instanceId;
424
+        if ($userId === $appdata) {
425
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
426
+        }
427
+
428
+        if (!empty($skeletonDirectory)) {
429
+            $logger->debug('copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'), ['app' => 'files_skeleton']);
430
+            self::copyr($skeletonDirectory, $userDirectory);
431
+            // update the file cache
432
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
433
+
434
+            /** @var ITemplateManager $templateManager */
435
+            $templateManager = \OC::$server->get(ITemplateManager::class);
436
+            $templateManager->initializeTemplateDirectory(null, $userId);
437
+        }
438
+    }
439
+
440
+    /**
441
+     * copies a directory recursively by using streams
442
+     *
443
+     * @param string $source
444
+     * @param \OCP\Files\Folder $target
445
+     * @return void
446
+     */
447
+    public static function copyr($source, \OCP\Files\Folder $target) {
448
+        $logger = \OC::$server->getLogger();
449
+
450
+        // Verify if folder exists
451
+        $dir = opendir($source);
452
+        if ($dir === false) {
453
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
454
+            return;
455
+        }
456
+
457
+        // Copy the files
458
+        while (false !== ($file = readdir($dir))) {
459
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
460
+                if (is_dir($source . '/' . $file)) {
461
+                    $child = $target->newFolder($file);
462
+                    self::copyr($source . '/' . $file, $child);
463
+                } else {
464
+                    $child = $target->newFile($file);
465
+                    $sourceStream = fopen($source . '/' . $file, 'r');
466
+                    if ($sourceStream === false) {
467
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
468
+                        closedir($dir);
469
+                        return;
470
+                    }
471
+                    stream_copy_to_stream($sourceStream, $child->fopen('w'));
472
+                }
473
+            }
474
+        }
475
+        closedir($dir);
476
+    }
477
+
478
+    /**
479
+     * @return void
480
+     * @suppress PhanUndeclaredMethod
481
+     */
482
+    public static function tearDownFS() {
483
+        \OC\Files\Filesystem::tearDown();
484
+        \OC::$server->getRootFolder()->clearCache();
485
+        self::$fsSetup = false;
486
+        self::$rootMounted = false;
487
+    }
488
+
489
+    /**
490
+     * get the current installed version of ownCloud
491
+     *
492
+     * @return array
493
+     */
494
+    public static function getVersion() {
495
+        OC_Util::loadVersion();
496
+        return self::$versionCache['OC_Version'];
497
+    }
498
+
499
+    /**
500
+     * get the current installed version string of ownCloud
501
+     *
502
+     * @return string
503
+     */
504
+    public static function getVersionString() {
505
+        OC_Util::loadVersion();
506
+        return self::$versionCache['OC_VersionString'];
507
+    }
508
+
509
+    /**
510
+     * @deprecated the value is of no use anymore
511
+     * @return string
512
+     */
513
+    public static function getEditionString() {
514
+        return '';
515
+    }
516
+
517
+    /**
518
+     * @description get the update channel of the current installed of ownCloud.
519
+     * @return string
520
+     */
521
+    public static function getChannel() {
522
+        OC_Util::loadVersion();
523
+        return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
524
+    }
525
+
526
+    /**
527
+     * @description get the build number of the current installed of ownCloud.
528
+     * @return string
529
+     */
530
+    public static function getBuild() {
531
+        OC_Util::loadVersion();
532
+        return self::$versionCache['OC_Build'];
533
+    }
534
+
535
+    /**
536
+     * @description load the version.php into the session as cache
537
+     * @suppress PhanUndeclaredVariable
538
+     */
539
+    private static function loadVersion() {
540
+        if (self::$versionCache !== null) {
541
+            return;
542
+        }
543
+
544
+        $timestamp = filemtime(OC::$SERVERROOT . '/version.php');
545
+        require OC::$SERVERROOT . '/version.php';
546
+        /** @var int $timestamp */
547
+        self::$versionCache['OC_Version_Timestamp'] = $timestamp;
548
+        /** @var string $OC_Version */
549
+        self::$versionCache['OC_Version'] = $OC_Version;
550
+        /** @var string $OC_VersionString */
551
+        self::$versionCache['OC_VersionString'] = $OC_VersionString;
552
+        /** @var string $OC_Build */
553
+        self::$versionCache['OC_Build'] = $OC_Build;
554
+
555
+        /** @var string $OC_Channel */
556
+        self::$versionCache['OC_Channel'] = $OC_Channel;
557
+    }
558
+
559
+    /**
560
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
561
+     *
562
+     * @param string $application application to get the files from
563
+     * @param string $directory directory within this application (css, js, vendor, etc)
564
+     * @param string $file the file inside of the above folder
565
+     * @return string the path
566
+     */
567
+    private static function generatePath($application, $directory, $file) {
568
+        if (is_null($file)) {
569
+            $file = $application;
570
+            $application = "";
571
+        }
572
+        if (!empty($application)) {
573
+            return "$application/$directory/$file";
574
+        } else {
575
+            return "$directory/$file";
576
+        }
577
+    }
578
+
579
+    /**
580
+     * add a javascript file
581
+     *
582
+     * @param string $application application id
583
+     * @param string|null $file filename
584
+     * @param bool $prepend prepend the Script to the beginning of the list
585
+     * @return void
586
+     */
587
+    public static function addScript($application, $file = null, $prepend = false) {
588
+        $path = OC_Util::generatePath($application, 'js', $file);
589
+
590
+        // core js files need separate handling
591
+        if ($application !== 'core' && $file !== null) {
592
+            self::addTranslations($application);
593
+        }
594
+        self::addExternalResource($application, $prepend, $path, "script");
595
+    }
596
+
597
+    /**
598
+     * add a javascript file from the vendor sub folder
599
+     *
600
+     * @param string $application application id
601
+     * @param string|null $file filename
602
+     * @param bool $prepend prepend the Script to the beginning of the list
603
+     * @return void
604
+     */
605
+    public static function addVendorScript($application, $file = null, $prepend = false) {
606
+        $path = OC_Util::generatePath($application, 'vendor', $file);
607
+        self::addExternalResource($application, $prepend, $path, "script");
608
+    }
609
+
610
+    /**
611
+     * add a translation JS file
612
+     *
613
+     * @param string $application application id
614
+     * @param string|null $languageCode language code, defaults to the current language
615
+     * @param bool|null $prepend prepend the Script to the beginning of the list
616
+     */
617
+    public static function addTranslations($application, $languageCode = null, $prepend = false) {
618
+        if (is_null($languageCode)) {
619
+            $languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
620
+        }
621
+        if (!empty($application)) {
622
+            $path = "$application/l10n/$languageCode";
623
+        } else {
624
+            $path = "l10n/$languageCode";
625
+        }
626
+        self::addExternalResource($application, $prepend, $path, "script");
627
+    }
628
+
629
+    /**
630
+     * add a css file
631
+     *
632
+     * @param string $application application id
633
+     * @param string|null $file filename
634
+     * @param bool $prepend prepend the Style to the beginning of the list
635
+     * @return void
636
+     */
637
+    public static function addStyle($application, $file = null, $prepend = false) {
638
+        $path = OC_Util::generatePath($application, 'css', $file);
639
+        self::addExternalResource($application, $prepend, $path, "style");
640
+    }
641
+
642
+    /**
643
+     * add a css file from the vendor sub folder
644
+     *
645
+     * @param string $application application id
646
+     * @param string|null $file filename
647
+     * @param bool $prepend prepend the Style to the beginning of the list
648
+     * @return void
649
+     */
650
+    public static function addVendorStyle($application, $file = null, $prepend = false) {
651
+        $path = OC_Util::generatePath($application, 'vendor', $file);
652
+        self::addExternalResource($application, $prepend, $path, "style");
653
+    }
654
+
655
+    /**
656
+     * add an external resource css/js file
657
+     *
658
+     * @param string $application application id
659
+     * @param bool $prepend prepend the file to the beginning of the list
660
+     * @param string $path
661
+     * @param string $type (script or style)
662
+     * @return void
663
+     */
664
+    private static function addExternalResource($application, $prepend, $path, $type = "script") {
665
+        if ($type === "style") {
666
+            if (!in_array($path, self::$styles)) {
667
+                if ($prepend === true) {
668
+                    array_unshift(self::$styles, $path);
669
+                } else {
670
+                    self::$styles[] = $path;
671
+                }
672
+            }
673
+        } elseif ($type === "script") {
674
+            if (!in_array($path, self::$scripts)) {
675
+                if ($prepend === true) {
676
+                    array_unshift(self::$scripts, $path);
677
+                } else {
678
+                    self::$scripts [] = $path;
679
+                }
680
+            }
681
+        }
682
+    }
683
+
684
+    /**
685
+     * Add a custom element to the header
686
+     * If $text is null then the element will be written as empty element.
687
+     * So use "" to get a closing tag.
688
+     * @param string $tag tag name of the element
689
+     * @param array $attributes array of attributes for the element
690
+     * @param string $text the text content for the element
691
+     * @param bool $prepend prepend the header to the beginning of the list
692
+     */
693
+    public static function addHeader($tag, $attributes, $text = null, $prepend = false) {
694
+        $header = [
695
+            'tag' => $tag,
696
+            'attributes' => $attributes,
697
+            'text' => $text
698
+        ];
699
+        if ($prepend === true) {
700
+            array_unshift(self::$headers, $header);
701
+        } else {
702
+            self::$headers[] = $header;
703
+        }
704
+    }
705
+
706
+    /**
707
+     * check if the current server configuration is suitable for ownCloud
708
+     *
709
+     * @param \OC\SystemConfig $config
710
+     * @return array arrays with error messages and hints
711
+     */
712
+    public static function checkServer(\OC\SystemConfig $config) {
713
+        $l = \OC::$server->getL10N('lib');
714
+        $errors = [];
715
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
716
+
717
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
718
+            // this check needs to be done every time
719
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
720
+        }
721
+
722
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
723
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
724
+            return $errors;
725
+        }
726
+
727
+        $webServerRestart = false;
728
+        $setup = new \OC\Setup(
729
+            $config,
730
+            \OC::$server->get(IniGetWrapper::class),
731
+            \OC::$server->getL10N('lib'),
732
+            \OC::$server->get(\OCP\Defaults::class),
733
+            \OC::$server->get(LoggerInterface::class),
734
+            \OC::$server->getSecureRandom(),
735
+            \OC::$server->get(\OC\Installer::class)
736
+        );
737
+
738
+        $urlGenerator = \OC::$server->getURLGenerator();
739
+
740
+        $availableDatabases = $setup->getSupportedDatabases();
741
+        if (empty($availableDatabases)) {
742
+            $errors[] = [
743
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
744
+                'hint' => '' //TODO: sane hint
745
+            ];
746
+            $webServerRestart = true;
747
+        }
748
+
749
+        // Check if config folder is writable.
750
+        if (!OC_Helper::isReadOnlyConfigEnabled()) {
751
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
752
+                $errors[] = [
753
+                    'error' => $l->t('Cannot write into "config" directory'),
754
+                    'hint' => $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
755
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ]) . '. '
756
+                        . $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',
757
+                        [ $urlGenerator->linkToDocs('admin-config') ])
758
+                ];
759
+            }
760
+        }
761
+
762
+        // Check if there is a writable install folder.
763
+        if ($config->getValue('appstoreenabled', true)) {
764
+            if (OC_App::getInstallPath() === null
765
+                || !is_writable(OC_App::getInstallPath())
766
+                || !is_readable(OC_App::getInstallPath())
767
+            ) {
768
+                $errors[] = [
769
+                    'error' => $l->t('Cannot write into "apps" directory'),
770
+                    'hint' => $l->t('This can usually be fixed by giving the webserver write access to the apps directory'
771
+                        . ' or disabling the App Store in the config file.')
772
+                ];
773
+            }
774
+        }
775
+        // Create root dir.
776
+        if ($config->getValue('installed', false)) {
777
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
778
+                $success = @mkdir($CONFIG_DATADIRECTORY);
779
+                if ($success) {
780
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
781
+                } else {
782
+                    $errors[] = [
783
+                        'error' => $l->t('Cannot create "data" directory'),
784
+                        'hint' => $l->t('This can usually be fixed by giving the webserver write access to the root directory. See %s',
785
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
786
+                    ];
787
+                }
788
+            } elseif (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
789
+                // is_writable doesn't work for NFS mounts, so try to write a file and check if it exists.
790
+                $testFile = sprintf('%s/%s.tmp', $CONFIG_DATADIRECTORY, uniqid('data_dir_writability_test_'));
791
+                $handle = fopen($testFile, 'w');
792
+                if (!$handle || fwrite($handle, 'Test write operation') === false) {
793
+                    $permissionsHint = $l->t('Permissions can usually be fixed by giving the webserver write access to the root directory. See %s.',
794
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')]);
795
+                    $errors[] = [
796
+                        'error' => 'Your data directory is not writable',
797
+                        'hint' => $permissionsHint
798
+                    ];
799
+                } else {
800
+                    fclose($handle);
801
+                    unlink($testFile);
802
+                }
803
+            } else {
804
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
805
+            }
806
+        }
807
+
808
+        if (!OC_Util::isSetLocaleWorking()) {
809
+            $errors[] = [
810
+                'error' => $l->t('Setting locale to %s failed',
811
+                    ['en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
812
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8']),
813
+                'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
814
+            ];
815
+        }
816
+
817
+        // Contains the dependencies that should be checked against
818
+        // classes = class_exists
819
+        // functions = function_exists
820
+        // defined = defined
821
+        // ini = ini_get
822
+        // If the dependency is not found the missing module name is shown to the EndUser
823
+        // When adding new checks always verify that they pass on Travis as well
824
+        // for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
825
+        $dependencies = [
826
+            'classes' => [
827
+                'ZipArchive' => 'zip',
828
+                'DOMDocument' => 'dom',
829
+                'XMLWriter' => 'XMLWriter',
830
+                'XMLReader' => 'XMLReader',
831
+            ],
832
+            'functions' => [
833
+                'xml_parser_create' => 'libxml',
834
+                'mb_strcut' => 'mbstring',
835
+                'ctype_digit' => 'ctype',
836
+                'json_encode' => 'JSON',
837
+                'gd_info' => 'GD',
838
+                'gzencode' => 'zlib',
839
+                'iconv' => 'iconv',
840
+                'simplexml_load_string' => 'SimpleXML',
841
+                'hash' => 'HASH Message Digest Framework',
842
+                'curl_init' => 'cURL',
843
+                'openssl_verify' => 'OpenSSL',
844
+            ],
845
+            'defined' => [
846
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
847
+            ],
848
+            'ini' => [
849
+                'default_charset' => 'UTF-8',
850
+            ],
851
+        ];
852
+        $missingDependencies = [];
853
+        $invalidIniSettings = [];
854
+
855
+        $iniWrapper = \OC::$server->get(IniGetWrapper::class);
856
+        foreach ($dependencies['classes'] as $class => $module) {
857
+            if (!class_exists($class)) {
858
+                $missingDependencies[] = $module;
859
+            }
860
+        }
861
+        foreach ($dependencies['functions'] as $function => $module) {
862
+            if (!function_exists($function)) {
863
+                $missingDependencies[] = $module;
864
+            }
865
+        }
866
+        foreach ($dependencies['defined'] as $defined => $module) {
867
+            if (!defined($defined)) {
868
+                $missingDependencies[] = $module;
869
+            }
870
+        }
871
+        foreach ($dependencies['ini'] as $setting => $expected) {
872
+            if (is_bool($expected)) {
873
+                if ($iniWrapper->getBool($setting) !== $expected) {
874
+                    $invalidIniSettings[] = [$setting, $expected];
875
+                }
876
+            }
877
+            if (is_int($expected)) {
878
+                if ($iniWrapper->getNumeric($setting) !== $expected) {
879
+                    $invalidIniSettings[] = [$setting, $expected];
880
+                }
881
+            }
882
+            if (is_string($expected)) {
883
+                if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
884
+                    $invalidIniSettings[] = [$setting, $expected];
885
+                }
886
+            }
887
+        }
888
+
889
+        foreach ($missingDependencies as $missingDependency) {
890
+            $errors[] = [
891
+                'error' => $l->t('PHP module %s not installed.', [$missingDependency]),
892
+                'hint' => $l->t('Please ask your server administrator to install the module.'),
893
+            ];
894
+            $webServerRestart = true;
895
+        }
896
+        foreach ($invalidIniSettings as $setting) {
897
+            if (is_bool($setting[1])) {
898
+                $setting[1] = $setting[1] ? 'on' : 'off';
899
+            }
900
+            $errors[] = [
901
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
902
+                'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
903
+            ];
904
+            $webServerRestart = true;
905
+        }
906
+
907
+        /**
908
+         * The mbstring.func_overload check can only be performed if the mbstring
909
+         * module is installed as it will return null if the checking setting is
910
+         * not available and thus a check on the boolean value fails.
911
+         *
912
+         * TODO: Should probably be implemented in the above generic dependency
913
+         *       check somehow in the long-term.
914
+         */
915
+        if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
916
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
917
+            $errors[] = [
918
+                'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
919
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
920
+            ];
921
+        }
922
+
923
+        if (function_exists('xml_parser_create') &&
924
+            LIBXML_LOADED_VERSION < 20700) {
925
+            $version = LIBXML_LOADED_VERSION;
926
+            $major = floor($version / 10000);
927
+            $version -= ($major * 10000);
928
+            $minor = floor($version / 100);
929
+            $version -= ($minor * 100);
930
+            $patch = $version;
931
+            $errors[] = [
932
+                'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
933
+                'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
934
+            ];
935
+        }
936
+
937
+        if (!self::isAnnotationsWorking()) {
938
+            $errors[] = [
939
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
940
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
941
+            ];
942
+        }
943
+
944
+        if (!\OC::$CLI && $webServerRestart) {
945
+            $errors[] = [
946
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
947
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
948
+            ];
949
+        }
950
+
951
+        $errors = array_merge($errors, self::checkDatabaseVersion());
952
+
953
+        // Cache the result of this function
954
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
955
+
956
+        return $errors;
957
+    }
958
+
959
+    /**
960
+     * Check the database version
961
+     *
962
+     * @return array errors array
963
+     */
964
+    public static function checkDatabaseVersion() {
965
+        $l = \OC::$server->getL10N('lib');
966
+        $errors = [];
967
+        $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
968
+        if ($dbType === 'pgsql') {
969
+            // check PostgreSQL version
970
+            try {
971
+                $result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
972
+                $data = $result->fetchRow();
973
+                $result->closeCursor();
974
+                if (isset($data['server_version'])) {
975
+                    $version = $data['server_version'];
976
+                    if (version_compare($version, '9.0.0', '<')) {
977
+                        $errors[] = [
978
+                            'error' => $l->t('PostgreSQL >= 9 required'),
979
+                            'hint' => $l->t('Please upgrade your database version')
980
+                        ];
981
+                    }
982
+                }
983
+            } catch (\Doctrine\DBAL\Exception $e) {
984
+                $logger = \OC::$server->getLogger();
985
+                $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
986
+                $logger->logException($e);
987
+            }
988
+        }
989
+        return $errors;
990
+    }
991
+
992
+    /**
993
+     * Check for correct file permissions of data directory
994
+     *
995
+     * @param string $dataDirectory
996
+     * @return array arrays with error messages and hints
997
+     */
998
+    public static function checkDataDirectoryPermissions($dataDirectory) {
999
+        if (\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
1000
+            return  [];
1001
+        }
1002
+
1003
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
1004
+        if (substr($perms, -1) !== '0') {
1005
+            chmod($dataDirectory, 0770);
1006
+            clearstatcache();
1007
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
1008
+            if ($perms[2] !== '0') {
1009
+                $l = \OC::$server->getL10N('lib');
1010
+                return [[
1011
+                    'error' => $l->t('Your data directory is readable by other users'),
1012
+                    'hint' => $l->t('Please change the permissions to 0770 so that the directory cannot be listed by other users.'),
1013
+                ]];
1014
+            }
1015
+        }
1016
+        return [];
1017
+    }
1018
+
1019
+    /**
1020
+     * Check that the data directory exists and is valid by
1021
+     * checking the existence of the ".ocdata" file.
1022
+     *
1023
+     * @param string $dataDirectory data directory path
1024
+     * @return array errors found
1025
+     */
1026
+    public static function checkDataDirectoryValidity($dataDirectory) {
1027
+        $l = \OC::$server->getL10N('lib');
1028
+        $errors = [];
1029
+        if ($dataDirectory[0] !== '/') {
1030
+            $errors[] = [
1031
+                'error' => $l->t('Your data directory must be an absolute path'),
1032
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration')
1033
+            ];
1034
+        }
1035
+        if (!file_exists($dataDirectory . '/.ocdata')) {
1036
+            $errors[] = [
1037
+                'error' => $l->t('Your data directory is invalid'),
1038
+                'hint' => $l->t('Ensure there is a file called ".ocdata"' .
1039
+                    ' in the root of the data directory.')
1040
+            ];
1041
+        }
1042
+        return $errors;
1043
+    }
1044
+
1045
+    /**
1046
+     * Check if the user is logged in, redirects to home if not. With
1047
+     * redirect URL parameter to the request URI.
1048
+     *
1049
+     * @return void
1050
+     */
1051
+    public static function checkLoggedIn() {
1052
+        // Check if we are a user
1053
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
1054
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
1055
+                        'core.login.showLoginForm',
1056
+                        [
1057
+                            'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
1058
+                        ]
1059
+                    )
1060
+            );
1061
+            exit();
1062
+        }
1063
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
1064
+        if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
1065
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
1066
+            exit();
1067
+        }
1068
+    }
1069
+
1070
+    /**
1071
+     * Check if the user is a admin, redirects to home if not
1072
+     *
1073
+     * @return void
1074
+     */
1075
+    public static function checkAdminUser() {
1076
+        OC_Util::checkLoggedIn();
1077
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
1078
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1079
+            exit();
1080
+        }
1081
+    }
1082
+
1083
+    /**
1084
+     * Returns the URL of the default page
1085
+     * based on the system configuration and
1086
+     * the apps visible for the current user
1087
+     *
1088
+     * @return string URL
1089
+     * @suppress PhanDeprecatedFunction
1090
+     */
1091
+    public static function getDefaultPageUrl() {
1092
+        /** @var IConfig $config */
1093
+        $config = \OC::$server->get(IConfig::class);
1094
+        $urlGenerator = \OC::$server->getURLGenerator();
1095
+        // Deny the redirect if the URL contains a @
1096
+        // This prevents unvalidated redirects like ?redirect_url=:[email protected]
1097
+        if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1098
+            $location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1099
+        } else {
1100
+            $defaultPage = \OC::$server->getConfig()->getAppValue('core', 'defaultpage');
1101
+            if ($defaultPage) {
1102
+                $location = $urlGenerator->getAbsoluteURL($defaultPage);
1103
+            } else {
1104
+                $appId = 'files';
1105
+                $defaultApps = explode(',', $config->getSystemValue('defaultapp', 'dashboard,files'));
1106
+
1107
+                /** @var IUserSession $userSession */
1108
+                $userSession = \OC::$server->get(IUserSession::class);
1109
+                $user = $userSession->getUser();
1110
+                if ($user) {
1111
+                    $userDefaultApps = explode(',', $config->getUserValue($user->getUID(), 'core', 'defaultapp'));
1112
+                    $defaultApps = array_filter(array_merge($userDefaultApps, $defaultApps));
1113
+                }
1114
+
1115
+                // find the first app that is enabled for the current user
1116
+                foreach ($defaultApps as $defaultApp) {
1117
+                    $defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1118
+                    if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1119
+                        $appId = $defaultApp;
1120
+                        break;
1121
+                    }
1122
+                }
1123
+
1124
+                if ($config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1125
+                    $location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1126
+                } else {
1127
+                    $location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1128
+                }
1129
+            }
1130
+        }
1131
+        return $location;
1132
+    }
1133
+
1134
+    /**
1135
+     * Redirect to the user default page
1136
+     *
1137
+     * @return void
1138
+     */
1139
+    public static function redirectToDefaultPage() {
1140
+        $location = self::getDefaultPageUrl();
1141
+        header('Location: ' . $location);
1142
+        exit();
1143
+    }
1144
+
1145
+    /**
1146
+     * get an id unique for this instance
1147
+     *
1148
+     * @return string
1149
+     */
1150
+    public static function getInstanceId() {
1151
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1152
+        if (is_null($id)) {
1153
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
1154
+            $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1155
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
1156
+        }
1157
+        return $id;
1158
+    }
1159
+
1160
+    /**
1161
+     * Public function to sanitize HTML
1162
+     *
1163
+     * This function is used to sanitize HTML and should be applied on any
1164
+     * string or array of strings before displaying it on a web page.
1165
+     *
1166
+     * @param string|array $value
1167
+     * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1168
+     */
1169
+    public static function sanitizeHTML($value) {
1170
+        if (is_array($value)) {
1171
+            $value = array_map(function ($value) {
1172
+                return self::sanitizeHTML($value);
1173
+            }, $value);
1174
+        } else {
1175
+            // Specify encoding for PHP<5.4
1176
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1177
+        }
1178
+        return $value;
1179
+    }
1180
+
1181
+    /**
1182
+     * Public function to encode url parameters
1183
+     *
1184
+     * This function is used to encode path to file before output.
1185
+     * Encoding is done according to RFC 3986 with one exception:
1186
+     * Character '/' is preserved as is.
1187
+     *
1188
+     * @param string $component part of URI to encode
1189
+     * @return string
1190
+     */
1191
+    public static function encodePath($component) {
1192
+        $encoded = rawurlencode($component);
1193
+        $encoded = str_replace('%2F', '/', $encoded);
1194
+        return $encoded;
1195
+    }
1196
+
1197
+
1198
+    public function createHtaccessTestFile(\OCP\IConfig $config) {
1199
+        // php dev server does not support htaccess
1200
+        if (php_sapi_name() === 'cli-server') {
1201
+            return false;
1202
+        }
1203
+
1204
+        // testdata
1205
+        $fileName = '/htaccesstest.txt';
1206
+        $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1207
+
1208
+        // creating a test file
1209
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1210
+
1211
+        if (file_exists($testFile)) {// already running this test, possible recursive call
1212
+            return false;
1213
+        }
1214
+
1215
+        $fp = @fopen($testFile, 'w');
1216
+        if (!$fp) {
1217
+            throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1218
+                'Make sure it is possible for the webserver to write to ' . $testFile);
1219
+        }
1220
+        fwrite($fp, $testContent);
1221
+        fclose($fp);
1222
+
1223
+        return $testContent;
1224
+    }
1225
+
1226
+    /**
1227
+     * Check if the .htaccess file is working
1228
+     * @param \OCP\IConfig $config
1229
+     * @return bool
1230
+     * @throws Exception
1231
+     * @throws \OC\HintException If the test file can't get written.
1232
+     */
1233
+    public function isHtaccessWorking(\OCP\IConfig $config) {
1234
+        if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1235
+            return true;
1236
+        }
1237
+
1238
+        $testContent = $this->createHtaccessTestFile($config);
1239
+        if ($testContent === false) {
1240
+            return false;
1241
+        }
1242
+
1243
+        $fileName = '/htaccesstest.txt';
1244
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1245
+
1246
+        // accessing the file via http
1247
+        $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1248
+        try {
1249
+            $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1250
+        } catch (\Exception $e) {
1251
+            $content = false;
1252
+        }
1253
+
1254
+        if (strpos($url, 'https:') === 0) {
1255
+            $url = 'http:' . substr($url, 6);
1256
+        } else {
1257
+            $url = 'https:' . substr($url, 5);
1258
+        }
1259
+
1260
+        try {
1261
+            $fallbackContent = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1262
+        } catch (\Exception $e) {
1263
+            $fallbackContent = false;
1264
+        }
1265
+
1266
+        // cleanup
1267
+        @unlink($testFile);
1268
+
1269
+        /*
1270 1270
 		 * If the content is not equal to test content our .htaccess
1271 1271
 		 * is working as required
1272 1272
 		 */
1273
-		return $content !== $testContent && $fallbackContent !== $testContent;
1274
-	}
1275
-
1276
-	/**
1277
-	 * Check if the setlocal call does not work. This can happen if the right
1278
-	 * local packages are not available on the server.
1279
-	 *
1280
-	 * @return bool
1281
-	 */
1282
-	public static function isSetLocaleWorking() {
1283
-		if ('' === basename('§')) {
1284
-			// Borrowed from \Patchwork\Utf8\Bootup::initLocale
1285
-			setlocale(LC_ALL, 'C.UTF-8', 'C');
1286
-			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');
1287
-		}
1288
-
1289
-		// Check again
1290
-		if ('' === basename('§')) {
1291
-			return false;
1292
-		}
1293
-		return true;
1294
-	}
1295
-
1296
-	/**
1297
-	 * Check if it's possible to get the inline annotations
1298
-	 *
1299
-	 * @return bool
1300
-	 */
1301
-	public static function isAnnotationsWorking() {
1302
-		$reflection = new \ReflectionMethod(__METHOD__);
1303
-		$docs = $reflection->getDocComment();
1304
-
1305
-		return (is_string($docs) && strlen($docs) > 50);
1306
-	}
1307
-
1308
-	/**
1309
-	 * Check if the PHP module fileinfo is loaded.
1310
-	 *
1311
-	 * @return bool
1312
-	 */
1313
-	public static function fileInfoLoaded() {
1314
-		return function_exists('finfo_open');
1315
-	}
1316
-
1317
-	/**
1318
-	 * clear all levels of output buffering
1319
-	 *
1320
-	 * @return void
1321
-	 */
1322
-	public static function obEnd() {
1323
-		while (ob_get_level()) {
1324
-			ob_end_clean();
1325
-		}
1326
-	}
1327
-
1328
-	/**
1329
-	 * Checks whether the server is running on Mac OS X
1330
-	 *
1331
-	 * @return bool true if running on Mac OS X, false otherwise
1332
-	 */
1333
-	public static function runningOnMac() {
1334
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1335
-	}
1336
-
1337
-	/**
1338
-	 * Handles the case that there may not be a theme, then check if a "default"
1339
-	 * theme exists and take that one
1340
-	 *
1341
-	 * @return string the theme
1342
-	 */
1343
-	public static function getTheme() {
1344
-		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1345
-
1346
-		if ($theme === '') {
1347
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1348
-				$theme = 'default';
1349
-			}
1350
-		}
1351
-
1352
-		return $theme;
1353
-	}
1354
-
1355
-	/**
1356
-	 * Normalize a unicode string
1357
-	 *
1358
-	 * @param string $value a not normalized string
1359
-	 * @return bool|string
1360
-	 */
1361
-	public static function normalizeUnicode($value) {
1362
-		if (Normalizer::isNormalized($value)) {
1363
-			return $value;
1364
-		}
1365
-
1366
-		$normalizedValue = Normalizer::normalize($value);
1367
-		if ($normalizedValue === null || $normalizedValue === false) {
1368
-			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1369
-			return $value;
1370
-		}
1371
-
1372
-		return $normalizedValue;
1373
-	}
1374
-
1375
-	/**
1376
-	 * A human readable string is generated based on version and build number
1377
-	 *
1378
-	 * @return string
1379
-	 */
1380
-	public static function getHumanVersion() {
1381
-		$version = OC_Util::getVersionString();
1382
-		$build = OC_Util::getBuild();
1383
-		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1384
-			$version .= ' Build:' . $build;
1385
-		}
1386
-		return $version;
1387
-	}
1388
-
1389
-	/**
1390
-	 * Returns whether the given file name is valid
1391
-	 *
1392
-	 * @param string $file file name to check
1393
-	 * @return bool true if the file name is valid, false otherwise
1394
-	 * @deprecated use \OC\Files\View::verifyPath()
1395
-	 */
1396
-	public static function isValidFileName($file) {
1397
-		$trimmed = trim($file);
1398
-		if ($trimmed === '') {
1399
-			return false;
1400
-		}
1401
-		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1402
-			return false;
1403
-		}
1404
-
1405
-		// detect part files
1406
-		if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1407
-			return false;
1408
-		}
1409
-
1410
-		foreach (str_split($trimmed) as $char) {
1411
-			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1412
-				return false;
1413
-			}
1414
-		}
1415
-		return true;
1416
-	}
1417
-
1418
-	/**
1419
-	 * Check whether the instance needs to perform an upgrade,
1420
-	 * either when the core version is higher or any app requires
1421
-	 * an upgrade.
1422
-	 *
1423
-	 * @param \OC\SystemConfig $config
1424
-	 * @return bool whether the core or any app needs an upgrade
1425
-	 * @throws \OC\HintException When the upgrade from the given version is not allowed
1426
-	 */
1427
-	public static function needUpgrade(\OC\SystemConfig $config) {
1428
-		if ($config->getValue('installed', false)) {
1429
-			$installedVersion = $config->getValue('version', '0.0.0');
1430
-			$currentVersion = implode('.', \OCP\Util::getVersion());
1431
-			$versionDiff = version_compare($currentVersion, $installedVersion);
1432
-			if ($versionDiff > 0) {
1433
-				return true;
1434
-			} elseif ($config->getValue('debug', false) && $versionDiff < 0) {
1435
-				// downgrade with debug
1436
-				$installedMajor = explode('.', $installedVersion);
1437
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1438
-				$currentMajor = explode('.', $currentVersion);
1439
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1440
-				if ($installedMajor === $currentMajor) {
1441
-					// Same major, allow downgrade for developers
1442
-					return true;
1443
-				} else {
1444
-					// downgrade attempt, throw exception
1445
-					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1446
-				}
1447
-			} elseif ($versionDiff < 0) {
1448
-				// downgrade attempt, throw exception
1449
-				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1450
-			}
1451
-
1452
-			// also check for upgrades for apps (independently from the user)
1453
-			$apps = \OC_App::getEnabledApps(false, true);
1454
-			$shouldUpgrade = false;
1455
-			foreach ($apps as $app) {
1456
-				if (\OC_App::shouldUpgrade($app)) {
1457
-					$shouldUpgrade = true;
1458
-					break;
1459
-				}
1460
-			}
1461
-			return $shouldUpgrade;
1462
-		} else {
1463
-			return false;
1464
-		}
1465
-	}
1466
-
1467
-	/**
1468
-	 * is this Internet explorer ?
1469
-	 *
1470
-	 * @return boolean
1471
-	 */
1472
-	public static function isIe() {
1473
-		if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1474
-			return false;
1475
-		}
1476
-
1477
-		return preg_match(Request::USER_AGENT_IE, $_SERVER['HTTP_USER_AGENT']) === 1;
1478
-	}
1273
+        return $content !== $testContent && $fallbackContent !== $testContent;
1274
+    }
1275
+
1276
+    /**
1277
+     * Check if the setlocal call does not work. This can happen if the right
1278
+     * local packages are not available on the server.
1279
+     *
1280
+     * @return bool
1281
+     */
1282
+    public static function isSetLocaleWorking() {
1283
+        if ('' === basename('§')) {
1284
+            // Borrowed from \Patchwork\Utf8\Bootup::initLocale
1285
+            setlocale(LC_ALL, 'C.UTF-8', 'C');
1286
+            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');
1287
+        }
1288
+
1289
+        // Check again
1290
+        if ('' === basename('§')) {
1291
+            return false;
1292
+        }
1293
+        return true;
1294
+    }
1295
+
1296
+    /**
1297
+     * Check if it's possible to get the inline annotations
1298
+     *
1299
+     * @return bool
1300
+     */
1301
+    public static function isAnnotationsWorking() {
1302
+        $reflection = new \ReflectionMethod(__METHOD__);
1303
+        $docs = $reflection->getDocComment();
1304
+
1305
+        return (is_string($docs) && strlen($docs) > 50);
1306
+    }
1307
+
1308
+    /**
1309
+     * Check if the PHP module fileinfo is loaded.
1310
+     *
1311
+     * @return bool
1312
+     */
1313
+    public static function fileInfoLoaded() {
1314
+        return function_exists('finfo_open');
1315
+    }
1316
+
1317
+    /**
1318
+     * clear all levels of output buffering
1319
+     *
1320
+     * @return void
1321
+     */
1322
+    public static function obEnd() {
1323
+        while (ob_get_level()) {
1324
+            ob_end_clean();
1325
+        }
1326
+    }
1327
+
1328
+    /**
1329
+     * Checks whether the server is running on Mac OS X
1330
+     *
1331
+     * @return bool true if running on Mac OS X, false otherwise
1332
+     */
1333
+    public static function runningOnMac() {
1334
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1335
+    }
1336
+
1337
+    /**
1338
+     * Handles the case that there may not be a theme, then check if a "default"
1339
+     * theme exists and take that one
1340
+     *
1341
+     * @return string the theme
1342
+     */
1343
+    public static function getTheme() {
1344
+        $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1345
+
1346
+        if ($theme === '') {
1347
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1348
+                $theme = 'default';
1349
+            }
1350
+        }
1351
+
1352
+        return $theme;
1353
+    }
1354
+
1355
+    /**
1356
+     * Normalize a unicode string
1357
+     *
1358
+     * @param string $value a not normalized string
1359
+     * @return bool|string
1360
+     */
1361
+    public static function normalizeUnicode($value) {
1362
+        if (Normalizer::isNormalized($value)) {
1363
+            return $value;
1364
+        }
1365
+
1366
+        $normalizedValue = Normalizer::normalize($value);
1367
+        if ($normalizedValue === null || $normalizedValue === false) {
1368
+            \OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1369
+            return $value;
1370
+        }
1371
+
1372
+        return $normalizedValue;
1373
+    }
1374
+
1375
+    /**
1376
+     * A human readable string is generated based on version and build number
1377
+     *
1378
+     * @return string
1379
+     */
1380
+    public static function getHumanVersion() {
1381
+        $version = OC_Util::getVersionString();
1382
+        $build = OC_Util::getBuild();
1383
+        if (!empty($build) and OC_Util::getChannel() === 'daily') {
1384
+            $version .= ' Build:' . $build;
1385
+        }
1386
+        return $version;
1387
+    }
1388
+
1389
+    /**
1390
+     * Returns whether the given file name is valid
1391
+     *
1392
+     * @param string $file file name to check
1393
+     * @return bool true if the file name is valid, false otherwise
1394
+     * @deprecated use \OC\Files\View::verifyPath()
1395
+     */
1396
+    public static function isValidFileName($file) {
1397
+        $trimmed = trim($file);
1398
+        if ($trimmed === '') {
1399
+            return false;
1400
+        }
1401
+        if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1402
+            return false;
1403
+        }
1404
+
1405
+        // detect part files
1406
+        if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1407
+            return false;
1408
+        }
1409
+
1410
+        foreach (str_split($trimmed) as $char) {
1411
+            if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1412
+                return false;
1413
+            }
1414
+        }
1415
+        return true;
1416
+    }
1417
+
1418
+    /**
1419
+     * Check whether the instance needs to perform an upgrade,
1420
+     * either when the core version is higher or any app requires
1421
+     * an upgrade.
1422
+     *
1423
+     * @param \OC\SystemConfig $config
1424
+     * @return bool whether the core or any app needs an upgrade
1425
+     * @throws \OC\HintException When the upgrade from the given version is not allowed
1426
+     */
1427
+    public static function needUpgrade(\OC\SystemConfig $config) {
1428
+        if ($config->getValue('installed', false)) {
1429
+            $installedVersion = $config->getValue('version', '0.0.0');
1430
+            $currentVersion = implode('.', \OCP\Util::getVersion());
1431
+            $versionDiff = version_compare($currentVersion, $installedVersion);
1432
+            if ($versionDiff > 0) {
1433
+                return true;
1434
+            } elseif ($config->getValue('debug', false) && $versionDiff < 0) {
1435
+                // downgrade with debug
1436
+                $installedMajor = explode('.', $installedVersion);
1437
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1438
+                $currentMajor = explode('.', $currentVersion);
1439
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1440
+                if ($installedMajor === $currentMajor) {
1441
+                    // Same major, allow downgrade for developers
1442
+                    return true;
1443
+                } else {
1444
+                    // downgrade attempt, throw exception
1445
+                    throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1446
+                }
1447
+            } elseif ($versionDiff < 0) {
1448
+                // downgrade attempt, throw exception
1449
+                throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1450
+            }
1451
+
1452
+            // also check for upgrades for apps (independently from the user)
1453
+            $apps = \OC_App::getEnabledApps(false, true);
1454
+            $shouldUpgrade = false;
1455
+            foreach ($apps as $app) {
1456
+                if (\OC_App::shouldUpgrade($app)) {
1457
+                    $shouldUpgrade = true;
1458
+                    break;
1459
+                }
1460
+            }
1461
+            return $shouldUpgrade;
1462
+        } else {
1463
+            return false;
1464
+        }
1465
+    }
1466
+
1467
+    /**
1468
+     * is this Internet explorer ?
1469
+     *
1470
+     * @return boolean
1471
+     */
1472
+    public static function isIe() {
1473
+        if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1474
+            return false;
1475
+        }
1476
+
1477
+        return preg_match(Request::USER_AGENT_IE, $_SERVER['HTTP_USER_AGENT']) === 1;
1478
+    }
1479 1479
 }
Please login to merge, or discard this patch.
apps/settings/lib/Controller/CheckSetupController.php 1 patch
Indentation   +680 added lines, -680 removed lines patch added patch discarded remove patch
@@ -82,304 +82,304 @@  discard block
 block discarded – undo
82 82
 use Symfony\Component\EventDispatcher\GenericEvent;
83 83
 
84 84
 class CheckSetupController extends Controller {
85
-	/** @var IConfig */
86
-	private $config;
87
-	/** @var IClientService */
88
-	private $clientService;
89
-	/** @var IURLGenerator */
90
-	private $urlGenerator;
91
-	/** @var IL10N */
92
-	private $l10n;
93
-	/** @var Checker */
94
-	private $checker;
95
-	/** @var LoggerInterface */
96
-	private $logger;
97
-	/** @var EventDispatcherInterface */
98
-	private $dispatcher;
99
-	/** @var Connection */
100
-	private $db;
101
-	/** @var ILockingProvider */
102
-	private $lockingProvider;
103
-	/** @var IDateTimeFormatter */
104
-	private $dateTimeFormatter;
105
-	/** @var MemoryInfo */
106
-	private $memoryInfo;
107
-	/** @var ISecureRandom */
108
-	private $secureRandom;
109
-	/** @var IniGetWrapper */
110
-	private $iniGetWrapper;
111
-	/** @var IDBConnection */
112
-	private $connection;
113
-
114
-	public function __construct($AppName,
115
-								IRequest $request,
116
-								IConfig $config,
117
-								IClientService $clientService,
118
-								IURLGenerator $urlGenerator,
119
-								IL10N $l10n,
120
-								Checker $checker,
121
-								LoggerInterface $logger,
122
-								EventDispatcherInterface $dispatcher,
123
-								Connection $db,
124
-								ILockingProvider $lockingProvider,
125
-								IDateTimeFormatter $dateTimeFormatter,
126
-								MemoryInfo $memoryInfo,
127
-								ISecureRandom $secureRandom,
128
-								IniGetWrapper $iniGetWrapper,
129
-								IDBConnection $connection) {
130
-		parent::__construct($AppName, $request);
131
-		$this->config = $config;
132
-		$this->clientService = $clientService;
133
-		$this->urlGenerator = $urlGenerator;
134
-		$this->l10n = $l10n;
135
-		$this->checker = $checker;
136
-		$this->logger = $logger;
137
-		$this->dispatcher = $dispatcher;
138
-		$this->db = $db;
139
-		$this->lockingProvider = $lockingProvider;
140
-		$this->dateTimeFormatter = $dateTimeFormatter;
141
-		$this->memoryInfo = $memoryInfo;
142
-		$this->secureRandom = $secureRandom;
143
-		$this->iniGetWrapper = $iniGetWrapper;
144
-		$this->connection = $connection;
145
-	}
146
-
147
-	/**
148
-	 * Checks if the server can connect to the internet using HTTPS and HTTP
149
-	 * @return bool
150
-	 */
151
-	private function hasInternetConnectivityProblems(): bool {
152
-		if ($this->config->getSystemValue('has_internet_connection', true) === false) {
153
-			return false;
154
-		}
155
-
156
-		$siteArray = $this->config->getSystemValue('connectivity_check_domains', [
157
-			'www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org'
158
-		]);
159
-
160
-		foreach ($siteArray as $site) {
161
-			if ($this->isSiteReachable($site)) {
162
-				return false;
163
-			}
164
-		}
165
-		return true;
166
-	}
167
-
168
-	/**
169
-	 * Checks if the Nextcloud server can connect to a specific URL using both HTTPS and HTTP
170
-	 * @return bool
171
-	 */
172
-	private function isSiteReachable($sitename) {
173
-		$httpSiteName = 'http://' . $sitename . '/';
174
-		$httpsSiteName = 'https://' . $sitename . '/';
175
-
176
-		try {
177
-			$client = $this->clientService->newClient();
178
-			$client->get($httpSiteName);
179
-			$client->get($httpsSiteName);
180
-		} catch (\Exception $e) {
181
-			$this->logger->error('Cannot connect to: ' . $sitename, [
182
-				'app' => 'internet_connection_check',
183
-				'exception' => $e,
184
-			]);
185
-			return false;
186
-		}
187
-		return true;
188
-	}
189
-
190
-	/**
191
-	 * Checks whether a local memcache is installed or not
192
-	 * @return bool
193
-	 */
194
-	private function isMemcacheConfigured() {
195
-		return $this->config->getSystemValue('memcache.local', null) !== null;
196
-	}
197
-
198
-	/**
199
-	 * Whether PHP can generate "secure" pseudorandom integers
200
-	 *
201
-	 * @return bool
202
-	 */
203
-	private function isRandomnessSecure() {
204
-		try {
205
-			$this->secureRandom->generate(1);
206
-		} catch (\Exception $ex) {
207
-			return false;
208
-		}
209
-		return true;
210
-	}
211
-
212
-	/**
213
-	 * Public for the sake of unit-testing
214
-	 *
215
-	 * @return array
216
-	 */
217
-	protected function getCurlVersion() {
218
-		return curl_version();
219
-	}
220
-
221
-	/**
222
-	 * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
223
-	 * have multiple bugs which likely lead to problems in combination with
224
-	 * functionality required by ownCloud such as SNI.
225
-	 *
226
-	 * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
227
-	 * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
228
-	 * @return string
229
-	 */
230
-	private function isUsedTlsLibOutdated() {
231
-		// Don't run check when:
232
-		// 1. Server has `has_internet_connection` set to false
233
-		// 2. AppStore AND S2S is disabled
234
-		if (!$this->config->getSystemValue('has_internet_connection', true)) {
235
-			return '';
236
-		}
237
-		if (!$this->config->getSystemValue('appstoreenabled', true)
238
-			&& $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
239
-			&& $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
240
-			return '';
241
-		}
242
-
243
-		$versionString = $this->getCurlVersion();
244
-		if (isset($versionString['ssl_version'])) {
245
-			$versionString = $versionString['ssl_version'];
246
-		} else {
247
-			return '';
248
-		}
249
-
250
-		$features = $this->l10n->t('installing and updating apps via the App Store or Federated Cloud Sharing');
251
-		if (!$this->config->getSystemValue('appstoreenabled', true)) {
252
-			$features = $this->l10n->t('Federated Cloud Sharing');
253
-		}
254
-
255
-		// Check if at least OpenSSL after 1.01d or 1.0.2b
256
-		if (strpos($versionString, 'OpenSSL/') === 0) {
257
-			$majorVersion = substr($versionString, 8, 5);
258
-			$patchRelease = substr($versionString, 13, 6);
259
-
260
-			if (($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
261
-				($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
262
-				return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['OpenSSL', $versionString, $features]);
263
-			}
264
-		}
265
-
266
-		// Check if NSS and perform heuristic check
267
-		if (strpos($versionString, 'NSS/') === 0) {
268
-			try {
269
-				$firstClient = $this->clientService->newClient();
270
-				$firstClient->get('https://nextcloud.com/');
271
-
272
-				$secondClient = $this->clientService->newClient();
273
-				$secondClient->get('https://nextcloud.com/');
274
-			} catch (ClientException $e) {
275
-				if ($e->getResponse()->getStatusCode() === 400) {
276
-					return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['NSS', $versionString, $features]);
277
-				}
278
-			} catch (\Exception $e) {
279
-				$this->logger->warning('error checking curl', [
280
-					'app' => 'settings',
281
-					'exception' => $e,
282
-				]);
283
-				return $this->l10n->t('Could not determine if TLS version of cURL is outdated or not because an error happened during the HTTPS request against https://nextcloud.com. Please check the nextcloud log file for more details.');
284
-			}
285
-		}
286
-
287
-		return '';
288
-	}
289
-
290
-	/**
291
-	 * Whether the version is outdated
292
-	 *
293
-	 * @return bool
294
-	 */
295
-	protected function isPhpOutdated(): bool {
296
-		return PHP_VERSION_ID < 70300;
297
-	}
298
-
299
-	/**
300
-	 * Whether the php version is still supported (at time of release)
301
-	 * according to: https://www.php.net/supported-versions.php
302
-	 *
303
-	 * @return array
304
-	 */
305
-	private function isPhpSupported(): array {
306
-		return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
307
-	}
308
-
309
-	/**
310
-	 * Check if the reverse proxy configuration is working as expected
311
-	 *
312
-	 * @return bool
313
-	 */
314
-	private function forwardedForHeadersWorking() {
315
-		$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
316
-		$remoteAddress = $this->request->getHeader('REMOTE_ADDR');
317
-
318
-		if (empty($trustedProxies) && $this->request->getHeader('X-Forwarded-Host') !== '') {
319
-			return false;
320
-		}
321
-
322
-		if (\is_array($trustedProxies) && \in_array($remoteAddress, $trustedProxies, true) && $remoteAddress !== '127.0.0.1') {
323
-			return $remoteAddress !== $this->request->getRemoteAddress();
324
-		}
325
-
326
-		// either not enabled or working correctly
327
-		return true;
328
-	}
329
-
330
-	/**
331
-	 * Checks if the correct memcache module for PHP is installed. Only
332
-	 * fails if memcached is configured and the working module is not installed.
333
-	 *
334
-	 * @return bool
335
-	 */
336
-	private function isCorrectMemcachedPHPModuleInstalled() {
337
-		if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
338
-			return true;
339
-		}
340
-
341
-		// there are two different memcached modules for PHP
342
-		// we only support memcached and not memcache
343
-		// https://code.google.com/p/memcached/wiki/PHPClientComparison
344
-		return !(!extension_loaded('memcached') && extension_loaded('memcache'));
345
-	}
346
-
347
-	/**
348
-	 * Checks if set_time_limit is not disabled.
349
-	 *
350
-	 * @return bool
351
-	 */
352
-	private function isSettimelimitAvailable() {
353
-		if (function_exists('set_time_limit')
354
-			&& strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
355
-			return true;
356
-		}
357
-
358
-		return false;
359
-	}
360
-
361
-	/**
362
-	 * @return RedirectResponse
363
-	 */
364
-	public function rescanFailedIntegrityCheck() {
365
-		$this->checker->runInstanceVerification();
366
-		return new RedirectResponse(
367
-			$this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'overview'])
368
-		);
369
-	}
370
-
371
-	/**
372
-	 * @NoCSRFRequired
373
-	 */
374
-	public function getFailedIntegrityCheckFiles(): DataDisplayResponse {
375
-		if (!$this->checker->isCodeCheckEnforced()) {
376
-			return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
377
-		}
378
-
379
-		$completeResults = $this->checker->getResults();
380
-
381
-		if (!empty($completeResults)) {
382
-			$formattedTextResponse = 'Technical information
85
+    /** @var IConfig */
86
+    private $config;
87
+    /** @var IClientService */
88
+    private $clientService;
89
+    /** @var IURLGenerator */
90
+    private $urlGenerator;
91
+    /** @var IL10N */
92
+    private $l10n;
93
+    /** @var Checker */
94
+    private $checker;
95
+    /** @var LoggerInterface */
96
+    private $logger;
97
+    /** @var EventDispatcherInterface */
98
+    private $dispatcher;
99
+    /** @var Connection */
100
+    private $db;
101
+    /** @var ILockingProvider */
102
+    private $lockingProvider;
103
+    /** @var IDateTimeFormatter */
104
+    private $dateTimeFormatter;
105
+    /** @var MemoryInfo */
106
+    private $memoryInfo;
107
+    /** @var ISecureRandom */
108
+    private $secureRandom;
109
+    /** @var IniGetWrapper */
110
+    private $iniGetWrapper;
111
+    /** @var IDBConnection */
112
+    private $connection;
113
+
114
+    public function __construct($AppName,
115
+                                IRequest $request,
116
+                                IConfig $config,
117
+                                IClientService $clientService,
118
+                                IURLGenerator $urlGenerator,
119
+                                IL10N $l10n,
120
+                                Checker $checker,
121
+                                LoggerInterface $logger,
122
+                                EventDispatcherInterface $dispatcher,
123
+                                Connection $db,
124
+                                ILockingProvider $lockingProvider,
125
+                                IDateTimeFormatter $dateTimeFormatter,
126
+                                MemoryInfo $memoryInfo,
127
+                                ISecureRandom $secureRandom,
128
+                                IniGetWrapper $iniGetWrapper,
129
+                                IDBConnection $connection) {
130
+        parent::__construct($AppName, $request);
131
+        $this->config = $config;
132
+        $this->clientService = $clientService;
133
+        $this->urlGenerator = $urlGenerator;
134
+        $this->l10n = $l10n;
135
+        $this->checker = $checker;
136
+        $this->logger = $logger;
137
+        $this->dispatcher = $dispatcher;
138
+        $this->db = $db;
139
+        $this->lockingProvider = $lockingProvider;
140
+        $this->dateTimeFormatter = $dateTimeFormatter;
141
+        $this->memoryInfo = $memoryInfo;
142
+        $this->secureRandom = $secureRandom;
143
+        $this->iniGetWrapper = $iniGetWrapper;
144
+        $this->connection = $connection;
145
+    }
146
+
147
+    /**
148
+     * Checks if the server can connect to the internet using HTTPS and HTTP
149
+     * @return bool
150
+     */
151
+    private function hasInternetConnectivityProblems(): bool {
152
+        if ($this->config->getSystemValue('has_internet_connection', true) === false) {
153
+            return false;
154
+        }
155
+
156
+        $siteArray = $this->config->getSystemValue('connectivity_check_domains', [
157
+            'www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org'
158
+        ]);
159
+
160
+        foreach ($siteArray as $site) {
161
+            if ($this->isSiteReachable($site)) {
162
+                return false;
163
+            }
164
+        }
165
+        return true;
166
+    }
167
+
168
+    /**
169
+     * Checks if the Nextcloud server can connect to a specific URL using both HTTPS and HTTP
170
+     * @return bool
171
+     */
172
+    private function isSiteReachable($sitename) {
173
+        $httpSiteName = 'http://' . $sitename . '/';
174
+        $httpsSiteName = 'https://' . $sitename . '/';
175
+
176
+        try {
177
+            $client = $this->clientService->newClient();
178
+            $client->get($httpSiteName);
179
+            $client->get($httpsSiteName);
180
+        } catch (\Exception $e) {
181
+            $this->logger->error('Cannot connect to: ' . $sitename, [
182
+                'app' => 'internet_connection_check',
183
+                'exception' => $e,
184
+            ]);
185
+            return false;
186
+        }
187
+        return true;
188
+    }
189
+
190
+    /**
191
+     * Checks whether a local memcache is installed or not
192
+     * @return bool
193
+     */
194
+    private function isMemcacheConfigured() {
195
+        return $this->config->getSystemValue('memcache.local', null) !== null;
196
+    }
197
+
198
+    /**
199
+     * Whether PHP can generate "secure" pseudorandom integers
200
+     *
201
+     * @return bool
202
+     */
203
+    private function isRandomnessSecure() {
204
+        try {
205
+            $this->secureRandom->generate(1);
206
+        } catch (\Exception $ex) {
207
+            return false;
208
+        }
209
+        return true;
210
+    }
211
+
212
+    /**
213
+     * Public for the sake of unit-testing
214
+     *
215
+     * @return array
216
+     */
217
+    protected function getCurlVersion() {
218
+        return curl_version();
219
+    }
220
+
221
+    /**
222
+     * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
223
+     * have multiple bugs which likely lead to problems in combination with
224
+     * functionality required by ownCloud such as SNI.
225
+     *
226
+     * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
227
+     * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
228
+     * @return string
229
+     */
230
+    private function isUsedTlsLibOutdated() {
231
+        // Don't run check when:
232
+        // 1. Server has `has_internet_connection` set to false
233
+        // 2. AppStore AND S2S is disabled
234
+        if (!$this->config->getSystemValue('has_internet_connection', true)) {
235
+            return '';
236
+        }
237
+        if (!$this->config->getSystemValue('appstoreenabled', true)
238
+            && $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
239
+            && $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
240
+            return '';
241
+        }
242
+
243
+        $versionString = $this->getCurlVersion();
244
+        if (isset($versionString['ssl_version'])) {
245
+            $versionString = $versionString['ssl_version'];
246
+        } else {
247
+            return '';
248
+        }
249
+
250
+        $features = $this->l10n->t('installing and updating apps via the App Store or Federated Cloud Sharing');
251
+        if (!$this->config->getSystemValue('appstoreenabled', true)) {
252
+            $features = $this->l10n->t('Federated Cloud Sharing');
253
+        }
254
+
255
+        // Check if at least OpenSSL after 1.01d or 1.0.2b
256
+        if (strpos($versionString, 'OpenSSL/') === 0) {
257
+            $majorVersion = substr($versionString, 8, 5);
258
+            $patchRelease = substr($versionString, 13, 6);
259
+
260
+            if (($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
261
+                ($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
262
+                return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['OpenSSL', $versionString, $features]);
263
+            }
264
+        }
265
+
266
+        // Check if NSS and perform heuristic check
267
+        if (strpos($versionString, 'NSS/') === 0) {
268
+            try {
269
+                $firstClient = $this->clientService->newClient();
270
+                $firstClient->get('https://nextcloud.com/');
271
+
272
+                $secondClient = $this->clientService->newClient();
273
+                $secondClient->get('https://nextcloud.com/');
274
+            } catch (ClientException $e) {
275
+                if ($e->getResponse()->getStatusCode() === 400) {
276
+                    return $this->l10n->t('cURL is using an outdated %1$s version (%2$s). Please update your operating system or features such as %3$s will not work reliably.', ['NSS', $versionString, $features]);
277
+                }
278
+            } catch (\Exception $e) {
279
+                $this->logger->warning('error checking curl', [
280
+                    'app' => 'settings',
281
+                    'exception' => $e,
282
+                ]);
283
+                return $this->l10n->t('Could not determine if TLS version of cURL is outdated or not because an error happened during the HTTPS request against https://nextcloud.com. Please check the nextcloud log file for more details.');
284
+            }
285
+        }
286
+
287
+        return '';
288
+    }
289
+
290
+    /**
291
+     * Whether the version is outdated
292
+     *
293
+     * @return bool
294
+     */
295
+    protected function isPhpOutdated(): bool {
296
+        return PHP_VERSION_ID < 70300;
297
+    }
298
+
299
+    /**
300
+     * Whether the php version is still supported (at time of release)
301
+     * according to: https://www.php.net/supported-versions.php
302
+     *
303
+     * @return array
304
+     */
305
+    private function isPhpSupported(): array {
306
+        return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
307
+    }
308
+
309
+    /**
310
+     * Check if the reverse proxy configuration is working as expected
311
+     *
312
+     * @return bool
313
+     */
314
+    private function forwardedForHeadersWorking() {
315
+        $trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
316
+        $remoteAddress = $this->request->getHeader('REMOTE_ADDR');
317
+
318
+        if (empty($trustedProxies) && $this->request->getHeader('X-Forwarded-Host') !== '') {
319
+            return false;
320
+        }
321
+
322
+        if (\is_array($trustedProxies) && \in_array($remoteAddress, $trustedProxies, true) && $remoteAddress !== '127.0.0.1') {
323
+            return $remoteAddress !== $this->request->getRemoteAddress();
324
+        }
325
+
326
+        // either not enabled or working correctly
327
+        return true;
328
+    }
329
+
330
+    /**
331
+     * Checks if the correct memcache module for PHP is installed. Only
332
+     * fails if memcached is configured and the working module is not installed.
333
+     *
334
+     * @return bool
335
+     */
336
+    private function isCorrectMemcachedPHPModuleInstalled() {
337
+        if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
338
+            return true;
339
+        }
340
+
341
+        // there are two different memcached modules for PHP
342
+        // we only support memcached and not memcache
343
+        // https://code.google.com/p/memcached/wiki/PHPClientComparison
344
+        return !(!extension_loaded('memcached') && extension_loaded('memcache'));
345
+    }
346
+
347
+    /**
348
+     * Checks if set_time_limit is not disabled.
349
+     *
350
+     * @return bool
351
+     */
352
+    private function isSettimelimitAvailable() {
353
+        if (function_exists('set_time_limit')
354
+            && strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
355
+            return true;
356
+        }
357
+
358
+        return false;
359
+    }
360
+
361
+    /**
362
+     * @return RedirectResponse
363
+     */
364
+    public function rescanFailedIntegrityCheck() {
365
+        $this->checker->runInstanceVerification();
366
+        return new RedirectResponse(
367
+            $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'overview'])
368
+        );
369
+    }
370
+
371
+    /**
372
+     * @NoCSRFRequired
373
+     */
374
+    public function getFailedIntegrityCheckFiles(): DataDisplayResponse {
375
+        if (!$this->checker->isCodeCheckEnforced()) {
376
+            return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
377
+        }
378
+
379
+        $completeResults = $this->checker->getResults();
380
+
381
+        if (!empty($completeResults)) {
382
+            $formattedTextResponse = 'Technical information
383 383
 =====================
384 384
 The following list covers which files have failed the integrity check. Please read
385 385
 the previous linked documentation to learn more about the errors and how to fix
@@ -388,389 +388,389 @@  discard block
 block discarded – undo
388 388
 Results
389 389
 =======
390 390
 ';
391
-			foreach ($completeResults as $context => $contextResult) {
392
-				$formattedTextResponse .= "- $context\n";
393
-
394
-				foreach ($contextResult as $category => $result) {
395
-					$formattedTextResponse .= "\t- $category\n";
396
-					if ($category !== 'EXCEPTION') {
397
-						foreach ($result as $key => $results) {
398
-							$formattedTextResponse .= "\t\t- $key\n";
399
-						}
400
-					} else {
401
-						foreach ($result as $key => $results) {
402
-							$formattedTextResponse .= "\t\t- $results\n";
403
-						}
404
-					}
405
-				}
406
-			}
407
-
408
-			$formattedTextResponse .= '
391
+            foreach ($completeResults as $context => $contextResult) {
392
+                $formattedTextResponse .= "- $context\n";
393
+
394
+                foreach ($contextResult as $category => $result) {
395
+                    $formattedTextResponse .= "\t- $category\n";
396
+                    if ($category !== 'EXCEPTION') {
397
+                        foreach ($result as $key => $results) {
398
+                            $formattedTextResponse .= "\t\t- $key\n";
399
+                        }
400
+                    } else {
401
+                        foreach ($result as $key => $results) {
402
+                            $formattedTextResponse .= "\t\t- $results\n";
403
+                        }
404
+                    }
405
+                }
406
+            }
407
+
408
+            $formattedTextResponse .= '
409 409
 Raw output
410 410
 ==========
411 411
 ';
412
-			$formattedTextResponse .= print_r($completeResults, true);
413
-		} else {
414
-			$formattedTextResponse = 'No errors have been found.';
415
-		}
416
-
417
-
418
-		return new DataDisplayResponse(
419
-			$formattedTextResponse,
420
-			Http::STATUS_OK,
421
-			[
422
-				'Content-Type' => 'text/plain',
423
-			]
424
-		);
425
-	}
426
-
427
-	/**
428
-	 * Checks whether a PHP opcache is properly set up
429
-	 * @return bool
430
-	 */
431
-	protected function isOpcacheProperlySetup() {
432
-		if (!$this->iniGetWrapper->getBool('opcache.enable')) {
433
-			return false;
434
-		}
435
-
436
-		if (!$this->iniGetWrapper->getBool('opcache.save_comments')) {
437
-			return false;
438
-		}
439
-
440
-		if ($this->iniGetWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
441
-			return false;
442
-		}
443
-
444
-		if ($this->iniGetWrapper->getNumeric('opcache.memory_consumption') < 128) {
445
-			return false;
446
-		}
447
-
448
-		if ($this->iniGetWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
449
-			return false;
450
-		}
451
-
452
-		return true;
453
-	}
454
-
455
-	/**
456
-	 * Check if the required FreeType functions are present
457
-	 * @return bool
458
-	 */
459
-	protected function hasFreeTypeSupport() {
460
-		return function_exists('imagettfbbox') && function_exists('imagettftext');
461
-	}
462
-
463
-	protected function hasMissingIndexes(): array {
464
-		$indexInfo = new MissingIndexInformation();
465
-		// Dispatch event so apps can also hint for pending index updates if needed
466
-		$event = new GenericEvent($indexInfo);
467
-		$this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
468
-
469
-		return $indexInfo->getListOfMissingIndexes();
470
-	}
471
-
472
-	protected function hasMissingPrimaryKeys(): array {
473
-		$info = new MissingPrimaryKeyInformation();
474
-		// Dispatch event so apps can also hint for pending index updates if needed
475
-		$event = new GenericEvent($info);
476
-		$this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_PRIMARY_KEYS_EVENT, $event);
477
-
478
-		return $info->getListOfMissingPrimaryKeys();
479
-	}
480
-
481
-	protected function hasMissingColumns(): array {
482
-		$indexInfo = new MissingColumnInformation();
483
-		// Dispatch event so apps can also hint for pending index updates if needed
484
-		$event = new GenericEvent($indexInfo);
485
-		$this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_COLUMNS_EVENT, $event);
486
-
487
-		return $indexInfo->getListOfMissingColumns();
488
-	}
489
-
490
-	protected function isSqliteUsed() {
491
-		return strpos($this->config->getSystemValue('dbtype'), 'sqlite') !== false;
492
-	}
493
-
494
-	protected function isReadOnlyConfig(): bool {
495
-		return \OC_Helper::isReadOnlyConfigEnabled();
496
-	}
497
-
498
-	protected function hasValidTransactionIsolationLevel(): bool {
499
-		try {
500
-			if ($this->db->getDatabasePlatform() instanceof SqlitePlatform) {
501
-				return true;
502
-			}
503
-
504
-			return $this->db->getTransactionIsolation() === TransactionIsolationLevel::READ_COMMITTED;
505
-		} catch (Exception $e) {
506
-			// ignore
507
-		}
508
-
509
-		return true;
510
-	}
511
-
512
-	protected function hasFileinfoInstalled(): bool {
513
-		return \OC_Util::fileInfoLoaded();
514
-	}
515
-
516
-	protected function hasWorkingFileLocking(): bool {
517
-		return !($this->lockingProvider instanceof NoopLockingProvider);
518
-	}
519
-
520
-	protected function getSuggestedOverwriteCliURL(): string {
521
-		$suggestedOverwriteCliUrl = '';
522
-		if ($this->config->getSystemValue('overwrite.cli.url', '') === '') {
523
-			$suggestedOverwriteCliUrl = $this->request->getServerProtocol() . '://' . $this->request->getInsecureServerHost() . \OC::$WEBROOT;
524
-			if (!$this->config->getSystemValue('config_is_read_only', false)) {
525
-				// Set the overwrite URL when it was not set yet.
526
-				$this->config->setSystemValue('overwrite.cli.url', $suggestedOverwriteCliUrl);
527
-				$suggestedOverwriteCliUrl = '';
528
-			}
529
-		}
530
-		return $suggestedOverwriteCliUrl;
531
-	}
532
-
533
-	protected function getLastCronInfo(): array {
534
-		$lastCronRun = $this->config->getAppValue('core', 'lastcron', 0);
535
-		return [
536
-			'diffInSeconds' => time() - $lastCronRun,
537
-			'relativeTime' => $this->dateTimeFormatter->formatTimeSpan($lastCronRun),
538
-			'backgroundJobsUrl' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'server']) . '#backgroundjobs',
539
-		];
540
-	}
541
-
542
-	protected function getCronErrors() {
543
-		$errors = json_decode($this->config->getAppValue('core', 'cronErrors', ''), true);
544
-
545
-		if (is_array($errors)) {
546
-			return $errors;
547
-		}
548
-
549
-		return [];
550
-	}
551
-
552
-	protected function hasOpcacheLoaded(): bool {
553
-		return extension_loaded('Zend OPcache');
554
-	}
555
-
556
-	/**
557
-	 * Iterates through the configured app roots and
558
-	 * tests if the subdirectories are owned by the same user than the current user.
559
-	 *
560
-	 * @return array
561
-	 */
562
-	protected function getAppDirsWithDifferentOwner(): array {
563
-		$currentUser = posix_getuid();
564
-		$appDirsWithDifferentOwner = [[]];
565
-
566
-		foreach (OC::$APPSROOTS as $appRoot) {
567
-			if ($appRoot['writable'] === true) {
568
-				$appDirsWithDifferentOwner[] = $this->getAppDirsWithDifferentOwnerForAppRoot($currentUser, $appRoot);
569
-			}
570
-		}
571
-
572
-		$appDirsWithDifferentOwner = array_merge(...$appDirsWithDifferentOwner);
573
-		sort($appDirsWithDifferentOwner);
574
-
575
-		return $appDirsWithDifferentOwner;
576
-	}
577
-
578
-	/**
579
-	 * Tests if the directories for one apps directory are writable by the current user.
580
-	 *
581
-	 * @param int $currentUser The current user
582
-	 * @param array $appRoot The app root config
583
-	 * @return string[] The none writable directory paths inside the app root
584
-	 */
585
-	private function getAppDirsWithDifferentOwnerForAppRoot(int $currentUser, array $appRoot): array {
586
-		$appDirsWithDifferentOwner = [];
587
-		$appsPath = $appRoot['path'];
588
-		$appsDir = new DirectoryIterator($appRoot['path']);
589
-
590
-		foreach ($appsDir as $fileInfo) {
591
-			if ($fileInfo->isDir() && !$fileInfo->isDot()) {
592
-				$absAppPath = $appsPath . DIRECTORY_SEPARATOR . $fileInfo->getFilename();
593
-				$appDirUser = fileowner($absAppPath);
594
-				if ($appDirUser !== $currentUser) {
595
-					$appDirsWithDifferentOwner[] = $absAppPath;
596
-				}
597
-			}
598
-		}
599
-
600
-		return $appDirsWithDifferentOwner;
601
-	}
602
-
603
-	/**
604
-	 * Checks for potential PHP modules that would improve the instance
605
-	 *
606
-	 * @return string[] A list of PHP modules that is recommended
607
-	 */
608
-	protected function hasRecommendedPHPModules(): array {
609
-		$recommendedPHPModules = [];
610
-
611
-		if (!extension_loaded('intl')) {
612
-			$recommendedPHPModules[] = 'intl';
613
-		}
614
-
615
-		if (!extension_loaded('bcmath')) {
616
-			$recommendedPHPModules[] = 'bcmath';
617
-		}
618
-
619
-		if (!extension_loaded('gmp')) {
620
-			$recommendedPHPModules[] = 'gmp';
621
-		}
622
-
623
-		if ($this->config->getAppValue('theming', 'enabled', 'no') === 'yes') {
624
-			if (!extension_loaded('imagick')) {
625
-				$recommendedPHPModules[] = 'imagick';
626
-			}
627
-		}
628
-
629
-		return $recommendedPHPModules;
630
-	}
631
-
632
-	protected function isMysqlUsedWithoutUTF8MB4(): bool {
633
-		return ($this->config->getSystemValue('dbtype', 'sqlite') === 'mysql') && ($this->config->getSystemValue('mysql.utf8mb4', false) === false);
634
-	}
635
-
636
-	protected function hasBigIntConversionPendingColumns(): array {
637
-		// copy of ConvertFilecacheBigInt::getColumnsByTable()
638
-		$tables = [
639
-			'activity' => ['activity_id', 'object_id'],
640
-			'activity_mq' => ['mail_id'],
641
-			'authtoken' => ['id'],
642
-			'bruteforce_attempts' => ['id'],
643
-			'federated_reshares' => ['share_id'],
644
-			'filecache' => ['fileid', 'storage', 'parent', 'mimetype', 'mimepart', 'mtime', 'storage_mtime'],
645
-			'filecache_extended' => ['fileid'],
646
-			'file_locks' => ['id'],
647
-			'jobs' => ['id'],
648
-			'mimetypes' => ['id'],
649
-			'mounts' => ['id', 'storage_id', 'root_id', 'mount_id'],
650
-			'share_external' => ['id', 'parent'],
651
-			'storages' => ['numeric_id'],
652
-		];
653
-
654
-		$schema = new SchemaWrapper($this->db);
655
-		$isSqlite = $this->db->getDatabasePlatform() instanceof SqlitePlatform;
656
-		$pendingColumns = [];
657
-
658
-		foreach ($tables as $tableName => $columns) {
659
-			if (!$schema->hasTable($tableName)) {
660
-				continue;
661
-			}
662
-
663
-			$table = $schema->getTable($tableName);
664
-			foreach ($columns as $columnName) {
665
-				$column = $table->getColumn($columnName);
666
-				$isAutoIncrement = $column->getAutoincrement();
667
-				$isAutoIncrementOnSqlite = $isSqlite && $isAutoIncrement;
668
-				if ($column->getType()->getName() !== Types::BIGINT && !$isAutoIncrementOnSqlite) {
669
-					$pendingColumns[] = $tableName . '.' . $columnName;
670
-				}
671
-			}
672
-		}
673
-
674
-		return $pendingColumns;
675
-	}
676
-
677
-	protected function isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(): bool {
678
-		$objectStore = $this->config->getSystemValue('objectstore', null);
679
-		$objectStoreMultibucket = $this->config->getSystemValue('objectstore_multibucket', null);
680
-
681
-		if (!isset($objectStoreMultibucket) && !isset($objectStore)) {
682
-			return true;
683
-		}
684
-
685
-		if (isset($objectStoreMultibucket['class']) && $objectStoreMultibucket['class'] !== 'OC\\Files\\ObjectStore\\S3') {
686
-			return true;
687
-		}
688
-
689
-		if (isset($objectStore['class']) && $objectStore['class'] !== 'OC\\Files\\ObjectStore\\S3') {
690
-			return true;
691
-		}
692
-
693
-		$tempPath = sys_get_temp_dir();
694
-		if (!is_dir($tempPath)) {
695
-			$this->logger->error('Error while checking the temporary PHP path - it was not properly set to a directory. value: ' . $tempPath);
696
-			return false;
697
-		}
698
-		$freeSpaceInTemp = disk_free_space($tempPath);
699
-		if ($freeSpaceInTemp === false) {
700
-			$this->logger->error('Error while checking the available disk space of temporary PHP path - no free disk space returned. temporary path: ' . $tempPath);
701
-			return false;
702
-		}
703
-
704
-		$freeSpaceInTempInGB = $freeSpaceInTemp / 1024 / 1024 / 1024;
705
-		if ($freeSpaceInTempInGB > 50) {
706
-			return true;
707
-		}
708
-
709
-		$this->logger->warning('Checking the available space in the temporary path resulted in ' . round($freeSpaceInTempInGB, 1) . ' GB instead of the recommended 50GB. Path: ' . $tempPath);
710
-		return false;
711
-	}
712
-
713
-	protected function imageMagickLacksSVGSupport(): bool {
714
-		return extension_loaded('imagick') && count(\Imagick::queryFormats('SVG')) === 0;
715
-	}
716
-
717
-	/**
718
-	 * @return DataResponse
719
-	 */
720
-	public function check() {
721
-		$phpDefaultCharset = new PhpDefaultCharset();
722
-		$phpOutputBuffering = new PhpOutputBuffering();
723
-		$legacySSEKeyFormat = new LegacySSEKeyFormat($this->l10n, $this->config, $this->urlGenerator);
724
-		$checkUserCertificates = new CheckUserCertificates($this->l10n, $this->config, $this->urlGenerator);
725
-		$supportedDatabases = new SupportedDatabase($this->l10n, $this->connection);
726
-
727
-		return new DataResponse(
728
-			[
729
-				'isGetenvServerWorking' => !empty(getenv('PATH')),
730
-				'isReadOnlyConfig' => $this->isReadOnlyConfig(),
731
-				'hasValidTransactionIsolationLevel' => $this->hasValidTransactionIsolationLevel(),
732
-				'hasFileinfoInstalled' => $this->hasFileinfoInstalled(),
733
-				'hasWorkingFileLocking' => $this->hasWorkingFileLocking(),
734
-				'suggestedOverwriteCliURL' => $this->getSuggestedOverwriteCliURL(),
735
-				'cronInfo' => $this->getLastCronInfo(),
736
-				'cronErrors' => $this->getCronErrors(),
737
-				'serverHasInternetConnectionProblems' => $this->hasInternetConnectivityProblems(),
738
-				'isMemcacheConfigured' => $this->isMemcacheConfigured(),
739
-				'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
740
-				'isRandomnessSecure' => $this->isRandomnessSecure(),
741
-				'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
742
-				'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
743
-				'phpSupported' => $this->isPhpSupported(),
744
-				'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
745
-				'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
746
-				'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
747
-				'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
748
-				'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
749
-				'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
750
-				'hasOpcacheLoaded' => $this->hasOpcacheLoaded(),
751
-				'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
752
-				'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
753
-				'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
754
-				'missingPrimaryKeys' => $this->hasMissingPrimaryKeys(),
755
-				'missingIndexes' => $this->hasMissingIndexes(),
756
-				'missingColumns' => $this->hasMissingColumns(),
757
-				'isSqliteUsed' => $this->isSqliteUsed(),
758
-				'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'),
759
-				'isMemoryLimitSufficient' => $this->memoryInfo->isMemoryLimitSufficient(),
760
-				'appDirsWithDifferentOwner' => $this->getAppDirsWithDifferentOwner(),
761
-				'recommendedPHPModules' => $this->hasRecommendedPHPModules(),
762
-				'pendingBigIntConversionColumns' => $this->hasBigIntConversionPendingColumns(),
763
-				'isMysqlUsedWithoutUTF8MB4' => $this->isMysqlUsedWithoutUTF8MB4(),
764
-				'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed' => $this->isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(),
765
-				'reverseProxyGeneratedURL' => $this->urlGenerator->getAbsoluteURL('index.php'),
766
-				'imageMagickLacksSVGSupport' => $this->imageMagickLacksSVGSupport(),
767
-				PhpDefaultCharset::class => ['pass' => $phpDefaultCharset->run(), 'description' => $phpDefaultCharset->description(), 'severity' => $phpDefaultCharset->severity()],
768
-				PhpOutputBuffering::class => ['pass' => $phpOutputBuffering->run(), 'description' => $phpOutputBuffering->description(), 'severity' => $phpOutputBuffering->severity()],
769
-				LegacySSEKeyFormat::class => ['pass' => $legacySSEKeyFormat->run(), 'description' => $legacySSEKeyFormat->description(), 'severity' => $legacySSEKeyFormat->severity(), 'linkToDocumentation' => $legacySSEKeyFormat->linkToDocumentation()],
770
-				CheckUserCertificates::class => ['pass' => $checkUserCertificates->run(), 'description' => $checkUserCertificates->description(), 'severity' => $checkUserCertificates->severity(), 'elements' => $checkUserCertificates->elements()],
771
-				'isDefaultPhoneRegionSet' => $this->config->getSystemValueString('default_phone_region', '') !== '',
772
-				SupportedDatabase::class => ['pass' => $supportedDatabases->run(), 'description' => $supportedDatabases->description(), 'severity' => $supportedDatabases->severity()],
773
-			]
774
-		);
775
-	}
412
+            $formattedTextResponse .= print_r($completeResults, true);
413
+        } else {
414
+            $formattedTextResponse = 'No errors have been found.';
415
+        }
416
+
417
+
418
+        return new DataDisplayResponse(
419
+            $formattedTextResponse,
420
+            Http::STATUS_OK,
421
+            [
422
+                'Content-Type' => 'text/plain',
423
+            ]
424
+        );
425
+    }
426
+
427
+    /**
428
+     * Checks whether a PHP opcache is properly set up
429
+     * @return bool
430
+     */
431
+    protected function isOpcacheProperlySetup() {
432
+        if (!$this->iniGetWrapper->getBool('opcache.enable')) {
433
+            return false;
434
+        }
435
+
436
+        if (!$this->iniGetWrapper->getBool('opcache.save_comments')) {
437
+            return false;
438
+        }
439
+
440
+        if ($this->iniGetWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
441
+            return false;
442
+        }
443
+
444
+        if ($this->iniGetWrapper->getNumeric('opcache.memory_consumption') < 128) {
445
+            return false;
446
+        }
447
+
448
+        if ($this->iniGetWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
449
+            return false;
450
+        }
451
+
452
+        return true;
453
+    }
454
+
455
+    /**
456
+     * Check if the required FreeType functions are present
457
+     * @return bool
458
+     */
459
+    protected function hasFreeTypeSupport() {
460
+        return function_exists('imagettfbbox') && function_exists('imagettftext');
461
+    }
462
+
463
+    protected function hasMissingIndexes(): array {
464
+        $indexInfo = new MissingIndexInformation();
465
+        // Dispatch event so apps can also hint for pending index updates if needed
466
+        $event = new GenericEvent($indexInfo);
467
+        $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
468
+
469
+        return $indexInfo->getListOfMissingIndexes();
470
+    }
471
+
472
+    protected function hasMissingPrimaryKeys(): array {
473
+        $info = new MissingPrimaryKeyInformation();
474
+        // Dispatch event so apps can also hint for pending index updates if needed
475
+        $event = new GenericEvent($info);
476
+        $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_PRIMARY_KEYS_EVENT, $event);
477
+
478
+        return $info->getListOfMissingPrimaryKeys();
479
+    }
480
+
481
+    protected function hasMissingColumns(): array {
482
+        $indexInfo = new MissingColumnInformation();
483
+        // Dispatch event so apps can also hint for pending index updates if needed
484
+        $event = new GenericEvent($indexInfo);
485
+        $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_COLUMNS_EVENT, $event);
486
+
487
+        return $indexInfo->getListOfMissingColumns();
488
+    }
489
+
490
+    protected function isSqliteUsed() {
491
+        return strpos($this->config->getSystemValue('dbtype'), 'sqlite') !== false;
492
+    }
493
+
494
+    protected function isReadOnlyConfig(): bool {
495
+        return \OC_Helper::isReadOnlyConfigEnabled();
496
+    }
497
+
498
+    protected function hasValidTransactionIsolationLevel(): bool {
499
+        try {
500
+            if ($this->db->getDatabasePlatform() instanceof SqlitePlatform) {
501
+                return true;
502
+            }
503
+
504
+            return $this->db->getTransactionIsolation() === TransactionIsolationLevel::READ_COMMITTED;
505
+        } catch (Exception $e) {
506
+            // ignore
507
+        }
508
+
509
+        return true;
510
+    }
511
+
512
+    protected function hasFileinfoInstalled(): bool {
513
+        return \OC_Util::fileInfoLoaded();
514
+    }
515
+
516
+    protected function hasWorkingFileLocking(): bool {
517
+        return !($this->lockingProvider instanceof NoopLockingProvider);
518
+    }
519
+
520
+    protected function getSuggestedOverwriteCliURL(): string {
521
+        $suggestedOverwriteCliUrl = '';
522
+        if ($this->config->getSystemValue('overwrite.cli.url', '') === '') {
523
+            $suggestedOverwriteCliUrl = $this->request->getServerProtocol() . '://' . $this->request->getInsecureServerHost() . \OC::$WEBROOT;
524
+            if (!$this->config->getSystemValue('config_is_read_only', false)) {
525
+                // Set the overwrite URL when it was not set yet.
526
+                $this->config->setSystemValue('overwrite.cli.url', $suggestedOverwriteCliUrl);
527
+                $suggestedOverwriteCliUrl = '';
528
+            }
529
+        }
530
+        return $suggestedOverwriteCliUrl;
531
+    }
532
+
533
+    protected function getLastCronInfo(): array {
534
+        $lastCronRun = $this->config->getAppValue('core', 'lastcron', 0);
535
+        return [
536
+            'diffInSeconds' => time() - $lastCronRun,
537
+            'relativeTime' => $this->dateTimeFormatter->formatTimeSpan($lastCronRun),
538
+            'backgroundJobsUrl' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'server']) . '#backgroundjobs',
539
+        ];
540
+    }
541
+
542
+    protected function getCronErrors() {
543
+        $errors = json_decode($this->config->getAppValue('core', 'cronErrors', ''), true);
544
+
545
+        if (is_array($errors)) {
546
+            return $errors;
547
+        }
548
+
549
+        return [];
550
+    }
551
+
552
+    protected function hasOpcacheLoaded(): bool {
553
+        return extension_loaded('Zend OPcache');
554
+    }
555
+
556
+    /**
557
+     * Iterates through the configured app roots and
558
+     * tests if the subdirectories are owned by the same user than the current user.
559
+     *
560
+     * @return array
561
+     */
562
+    protected function getAppDirsWithDifferentOwner(): array {
563
+        $currentUser = posix_getuid();
564
+        $appDirsWithDifferentOwner = [[]];
565
+
566
+        foreach (OC::$APPSROOTS as $appRoot) {
567
+            if ($appRoot['writable'] === true) {
568
+                $appDirsWithDifferentOwner[] = $this->getAppDirsWithDifferentOwnerForAppRoot($currentUser, $appRoot);
569
+            }
570
+        }
571
+
572
+        $appDirsWithDifferentOwner = array_merge(...$appDirsWithDifferentOwner);
573
+        sort($appDirsWithDifferentOwner);
574
+
575
+        return $appDirsWithDifferentOwner;
576
+    }
577
+
578
+    /**
579
+     * Tests if the directories for one apps directory are writable by the current user.
580
+     *
581
+     * @param int $currentUser The current user
582
+     * @param array $appRoot The app root config
583
+     * @return string[] The none writable directory paths inside the app root
584
+     */
585
+    private function getAppDirsWithDifferentOwnerForAppRoot(int $currentUser, array $appRoot): array {
586
+        $appDirsWithDifferentOwner = [];
587
+        $appsPath = $appRoot['path'];
588
+        $appsDir = new DirectoryIterator($appRoot['path']);
589
+
590
+        foreach ($appsDir as $fileInfo) {
591
+            if ($fileInfo->isDir() && !$fileInfo->isDot()) {
592
+                $absAppPath = $appsPath . DIRECTORY_SEPARATOR . $fileInfo->getFilename();
593
+                $appDirUser = fileowner($absAppPath);
594
+                if ($appDirUser !== $currentUser) {
595
+                    $appDirsWithDifferentOwner[] = $absAppPath;
596
+                }
597
+            }
598
+        }
599
+
600
+        return $appDirsWithDifferentOwner;
601
+    }
602
+
603
+    /**
604
+     * Checks for potential PHP modules that would improve the instance
605
+     *
606
+     * @return string[] A list of PHP modules that is recommended
607
+     */
608
+    protected function hasRecommendedPHPModules(): array {
609
+        $recommendedPHPModules = [];
610
+
611
+        if (!extension_loaded('intl')) {
612
+            $recommendedPHPModules[] = 'intl';
613
+        }
614
+
615
+        if (!extension_loaded('bcmath')) {
616
+            $recommendedPHPModules[] = 'bcmath';
617
+        }
618
+
619
+        if (!extension_loaded('gmp')) {
620
+            $recommendedPHPModules[] = 'gmp';
621
+        }
622
+
623
+        if ($this->config->getAppValue('theming', 'enabled', 'no') === 'yes') {
624
+            if (!extension_loaded('imagick')) {
625
+                $recommendedPHPModules[] = 'imagick';
626
+            }
627
+        }
628
+
629
+        return $recommendedPHPModules;
630
+    }
631
+
632
+    protected function isMysqlUsedWithoutUTF8MB4(): bool {
633
+        return ($this->config->getSystemValue('dbtype', 'sqlite') === 'mysql') && ($this->config->getSystemValue('mysql.utf8mb4', false) === false);
634
+    }
635
+
636
+    protected function hasBigIntConversionPendingColumns(): array {
637
+        // copy of ConvertFilecacheBigInt::getColumnsByTable()
638
+        $tables = [
639
+            'activity' => ['activity_id', 'object_id'],
640
+            'activity_mq' => ['mail_id'],
641
+            'authtoken' => ['id'],
642
+            'bruteforce_attempts' => ['id'],
643
+            'federated_reshares' => ['share_id'],
644
+            'filecache' => ['fileid', 'storage', 'parent', 'mimetype', 'mimepart', 'mtime', 'storage_mtime'],
645
+            'filecache_extended' => ['fileid'],
646
+            'file_locks' => ['id'],
647
+            'jobs' => ['id'],
648
+            'mimetypes' => ['id'],
649
+            'mounts' => ['id', 'storage_id', 'root_id', 'mount_id'],
650
+            'share_external' => ['id', 'parent'],
651
+            'storages' => ['numeric_id'],
652
+        ];
653
+
654
+        $schema = new SchemaWrapper($this->db);
655
+        $isSqlite = $this->db->getDatabasePlatform() instanceof SqlitePlatform;
656
+        $pendingColumns = [];
657
+
658
+        foreach ($tables as $tableName => $columns) {
659
+            if (!$schema->hasTable($tableName)) {
660
+                continue;
661
+            }
662
+
663
+            $table = $schema->getTable($tableName);
664
+            foreach ($columns as $columnName) {
665
+                $column = $table->getColumn($columnName);
666
+                $isAutoIncrement = $column->getAutoincrement();
667
+                $isAutoIncrementOnSqlite = $isSqlite && $isAutoIncrement;
668
+                if ($column->getType()->getName() !== Types::BIGINT && !$isAutoIncrementOnSqlite) {
669
+                    $pendingColumns[] = $tableName . '.' . $columnName;
670
+                }
671
+            }
672
+        }
673
+
674
+        return $pendingColumns;
675
+    }
676
+
677
+    protected function isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(): bool {
678
+        $objectStore = $this->config->getSystemValue('objectstore', null);
679
+        $objectStoreMultibucket = $this->config->getSystemValue('objectstore_multibucket', null);
680
+
681
+        if (!isset($objectStoreMultibucket) && !isset($objectStore)) {
682
+            return true;
683
+        }
684
+
685
+        if (isset($objectStoreMultibucket['class']) && $objectStoreMultibucket['class'] !== 'OC\\Files\\ObjectStore\\S3') {
686
+            return true;
687
+        }
688
+
689
+        if (isset($objectStore['class']) && $objectStore['class'] !== 'OC\\Files\\ObjectStore\\S3') {
690
+            return true;
691
+        }
692
+
693
+        $tempPath = sys_get_temp_dir();
694
+        if (!is_dir($tempPath)) {
695
+            $this->logger->error('Error while checking the temporary PHP path - it was not properly set to a directory. value: ' . $tempPath);
696
+            return false;
697
+        }
698
+        $freeSpaceInTemp = disk_free_space($tempPath);
699
+        if ($freeSpaceInTemp === false) {
700
+            $this->logger->error('Error while checking the available disk space of temporary PHP path - no free disk space returned. temporary path: ' . $tempPath);
701
+            return false;
702
+        }
703
+
704
+        $freeSpaceInTempInGB = $freeSpaceInTemp / 1024 / 1024 / 1024;
705
+        if ($freeSpaceInTempInGB > 50) {
706
+            return true;
707
+        }
708
+
709
+        $this->logger->warning('Checking the available space in the temporary path resulted in ' . round($freeSpaceInTempInGB, 1) . ' GB instead of the recommended 50GB. Path: ' . $tempPath);
710
+        return false;
711
+    }
712
+
713
+    protected function imageMagickLacksSVGSupport(): bool {
714
+        return extension_loaded('imagick') && count(\Imagick::queryFormats('SVG')) === 0;
715
+    }
716
+
717
+    /**
718
+     * @return DataResponse
719
+     */
720
+    public function check() {
721
+        $phpDefaultCharset = new PhpDefaultCharset();
722
+        $phpOutputBuffering = new PhpOutputBuffering();
723
+        $legacySSEKeyFormat = new LegacySSEKeyFormat($this->l10n, $this->config, $this->urlGenerator);
724
+        $checkUserCertificates = new CheckUserCertificates($this->l10n, $this->config, $this->urlGenerator);
725
+        $supportedDatabases = new SupportedDatabase($this->l10n, $this->connection);
726
+
727
+        return new DataResponse(
728
+            [
729
+                'isGetenvServerWorking' => !empty(getenv('PATH')),
730
+                'isReadOnlyConfig' => $this->isReadOnlyConfig(),
731
+                'hasValidTransactionIsolationLevel' => $this->hasValidTransactionIsolationLevel(),
732
+                'hasFileinfoInstalled' => $this->hasFileinfoInstalled(),
733
+                'hasWorkingFileLocking' => $this->hasWorkingFileLocking(),
734
+                'suggestedOverwriteCliURL' => $this->getSuggestedOverwriteCliURL(),
735
+                'cronInfo' => $this->getLastCronInfo(),
736
+                'cronErrors' => $this->getCronErrors(),
737
+                'serverHasInternetConnectionProblems' => $this->hasInternetConnectivityProblems(),
738
+                'isMemcacheConfigured' => $this->isMemcacheConfigured(),
739
+                'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
740
+                'isRandomnessSecure' => $this->isRandomnessSecure(),
741
+                'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
742
+                'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
743
+                'phpSupported' => $this->isPhpSupported(),
744
+                'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
745
+                'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
746
+                'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
747
+                'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
748
+                'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
749
+                'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
750
+                'hasOpcacheLoaded' => $this->hasOpcacheLoaded(),
751
+                'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
752
+                'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
753
+                'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
754
+                'missingPrimaryKeys' => $this->hasMissingPrimaryKeys(),
755
+                'missingIndexes' => $this->hasMissingIndexes(),
756
+                'missingColumns' => $this->hasMissingColumns(),
757
+                'isSqliteUsed' => $this->isSqliteUsed(),
758
+                'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'),
759
+                'isMemoryLimitSufficient' => $this->memoryInfo->isMemoryLimitSufficient(),
760
+                'appDirsWithDifferentOwner' => $this->getAppDirsWithDifferentOwner(),
761
+                'recommendedPHPModules' => $this->hasRecommendedPHPModules(),
762
+                'pendingBigIntConversionColumns' => $this->hasBigIntConversionPendingColumns(),
763
+                'isMysqlUsedWithoutUTF8MB4' => $this->isMysqlUsedWithoutUTF8MB4(),
764
+                'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed' => $this->isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(),
765
+                'reverseProxyGeneratedURL' => $this->urlGenerator->getAbsoluteURL('index.php'),
766
+                'imageMagickLacksSVGSupport' => $this->imageMagickLacksSVGSupport(),
767
+                PhpDefaultCharset::class => ['pass' => $phpDefaultCharset->run(), 'description' => $phpDefaultCharset->description(), 'severity' => $phpDefaultCharset->severity()],
768
+                PhpOutputBuffering::class => ['pass' => $phpOutputBuffering->run(), 'description' => $phpOutputBuffering->description(), 'severity' => $phpOutputBuffering->severity()],
769
+                LegacySSEKeyFormat::class => ['pass' => $legacySSEKeyFormat->run(), 'description' => $legacySSEKeyFormat->description(), 'severity' => $legacySSEKeyFormat->severity(), 'linkToDocumentation' => $legacySSEKeyFormat->linkToDocumentation()],
770
+                CheckUserCertificates::class => ['pass' => $checkUserCertificates->run(), 'description' => $checkUserCertificates->description(), 'severity' => $checkUserCertificates->severity(), 'elements' => $checkUserCertificates->elements()],
771
+                'isDefaultPhoneRegionSet' => $this->config->getSystemValueString('default_phone_region', '') !== '',
772
+                SupportedDatabase::class => ['pass' => $supportedDatabases->run(), 'description' => $supportedDatabases->description(), 'severity' => $supportedDatabases->severity()],
773
+            ]
774
+        );
775
+    }
776 776
 }
Please login to merge, or discard this patch.