Passed
Push — master ( fc57f6...7d9004 )
by Roeland
13:16 queued 10s
created
lib/private/legacy/OC_Files.php 1 patch
Indentation   +373 added lines, -373 removed lines patch added patch discarded remove patch
@@ -51,377 +51,377 @@
 block discarded – undo
51 51
  *
52 52
  */
53 53
 class OC_Files {
54
-	public const FILE = 1;
55
-	public const ZIP_FILES = 2;
56
-	public const ZIP_DIR = 3;
57
-
58
-	public const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
59
-
60
-
61
-	private static $multipartBoundary = '';
62
-
63
-	/**
64
-	 * @return string
65
-	 */
66
-	private static function getBoundary() {
67
-		if (empty(self::$multipartBoundary)) {
68
-			self::$multipartBoundary = md5(mt_rand());
69
-		}
70
-		return self::$multipartBoundary;
71
-	}
72
-
73
-	/**
74
-	 * @param string $filename
75
-	 * @param string $name
76
-	 * @param array $rangeArray ('from'=>int,'to'=>int), ...
77
-	 */
78
-	private static function sendHeaders($filename, $name, array $rangeArray) {
79
-		OC_Response::setContentDispositionHeader($name, 'attachment');
80
-		header('Content-Transfer-Encoding: binary', true);
81
-		header('Pragma: public');// enable caching in IE
82
-		header('Expires: 0');
83
-		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
84
-		$fileSize = \OC\Files\Filesystem::filesize($filename);
85
-		$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
86
-		if ($fileSize > -1) {
87
-			if (!empty($rangeArray)) {
88
-				http_response_code(206);
89
-				header('Accept-Ranges: bytes', true);
90
-				if (count($rangeArray) > 1) {
91
-					$type = 'multipart/byteranges; boundary='.self::getBoundary();
92
-				// no Content-Length header here
93
-				} else {
94
-					header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
95
-					OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
96
-				}
97
-			} else {
98
-				OC_Response::setContentLengthHeader($fileSize);
99
-			}
100
-		}
101
-		header('Content-Type: '.$type, true);
102
-	}
103
-
104
-	/**
105
-	 * return the content of a file or return a zip file containing multiple files
106
-	 *
107
-	 * @param string $dir
108
-	 * @param string $files ; separated list of files to download
109
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
110
-	 */
111
-	public static function get($dir, $files, $params = null) {
112
-		OC_Util::setupFS();
113
-		$view = \OC\Files\Filesystem::getView();
114
-		$getType = self::FILE;
115
-		$filename = $dir;
116
-		try {
117
-			if (is_array($files) && count($files) === 1) {
118
-				$files = $files[0];
119
-			}
120
-
121
-			if (!is_array($files)) {
122
-				$filename = $dir . '/' . $files;
123
-				if (!$view->is_dir($filename)) {
124
-					self::getSingleFile($view, $dir, $files, is_null($params) ? [] : $params);
125
-					return;
126
-				}
127
-			}
128
-
129
-			$name = 'download';
130
-			if (is_array($files)) {
131
-				$getType = self::ZIP_FILES;
132
-				$basename = basename($dir);
133
-				if ($basename) {
134
-					$name = $basename;
135
-				}
136
-
137
-				$filename = $dir . '/' . $name;
138
-			} else {
139
-				$filename = $dir . '/' . $files;
140
-				$getType = self::ZIP_DIR;
141
-				// downloading root ?
142
-				if ($files !== '') {
143
-					$name = $files;
144
-				}
145
-			}
146
-
147
-			self::lockFiles($view, $dir, $files);
148
-
149
-			/* Calculate filesize and number of files */
150
-			if ($getType === self::ZIP_FILES) {
151
-				$fileInfos = [];
152
-				$fileSize = 0;
153
-				foreach ($files as $file) {
154
-					$fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);
155
-					$fileSize += $fileInfo->getSize();
156
-					$fileInfos[] = $fileInfo;
157
-				}
158
-				$numberOfFiles = self::getNumberOfFiles($fileInfos);
159
-			} elseif ($getType === self::ZIP_DIR) {
160
-				$fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);
161
-				$fileSize = $fileInfo->getSize();
162
-				$numberOfFiles = self::getNumberOfFiles([$fileInfo]);
163
-			}
164
-
165
-			$streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);
166
-			OC_Util::obEnd();
167
-
168
-			$streamer->sendHeaders($name);
169
-			$executionTime = (int)OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time');
170
-			if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
171
-				@set_time_limit(0);
172
-			}
173
-			ignore_user_abort(true);
174
-
175
-			if ($getType === self::ZIP_FILES) {
176
-				foreach ($files as $file) {
177
-					$file = $dir . '/' . $file;
178
-					if (\OC\Files\Filesystem::is_file($file)) {
179
-						$userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
180
-						$file = $userFolder->get($file);
181
-						if ($file instanceof \OC\Files\Node\File) {
182
-							try {
183
-								$fh = $file->fopen('r');
184
-							} catch (\OCP\Files\NotPermittedException $e) {
185
-								continue;
186
-							}
187
-							$fileSize = $file->getSize();
188
-							$fileTime = $file->getMTime();
189
-						} else {
190
-							// File is not a file? …
191
-							\OC::$server->getLogger()->debug(
192
-								'File given, but no Node available. Name {file}',
193
-								[ 'app' => 'files', 'file' => $file ]
194
-							);
195
-							continue;
196
-						}
197
-						$streamer->addFileFromStream($fh, $file->getName(), $fileSize, $fileTime);
198
-						fclose($fh);
199
-					} elseif (\OC\Files\Filesystem::is_dir($file)) {
200
-						$streamer->addDirRecursive($file);
201
-					}
202
-				}
203
-			} elseif ($getType === self::ZIP_DIR) {
204
-				$file = $dir . '/' . $files;
205
-				$streamer->addDirRecursive($file);
206
-			}
207
-			$streamer->finalize();
208
-			set_time_limit($executionTime);
209
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
210
-		} catch (\OCP\Lock\LockedException $ex) {
211
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
212
-			OC::$server->getLogger()->logException($ex);
213
-			$l = \OC::$server->getL10N('lib');
214
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
215
-			\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
216
-		} catch (\OCP\Files\ForbiddenException $ex) {
217
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
218
-			OC::$server->getLogger()->logException($ex);
219
-			$l = \OC::$server->getL10N('lib');
220
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200);
221
-		} catch (\Exception $ex) {
222
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
223
-			OC::$server->getLogger()->logException($ex);
224
-			$l = \OC::$server->getL10N('lib');
225
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
226
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200);
227
-		}
228
-	}
229
-
230
-	/**
231
-	 * @param string $rangeHeaderPos
232
-	 * @param int $fileSize
233
-	 * @return array $rangeArray ('from'=>int,'to'=>int), ...
234
-	 */
235
-	private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
236
-		$rArray = explode(',', $rangeHeaderPos);
237
-		$minOffset = 0;
238
-		$ind = 0;
239
-
240
-		$rangeArray = [];
241
-
242
-		foreach ($rArray as $value) {
243
-			$ranges = explode('-', $value);
244
-			if (is_numeric($ranges[0])) {
245
-				if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
246
-					$ranges[0] = $minOffset;
247
-				}
248
-				if ($ind > 0 && $rangeArray[$ind - 1]['to'] + 1 == $ranges[0]) { // case: bytes=500-600,601-999
249
-					$ind--;
250
-					$ranges[0] = $rangeArray[$ind]['from'];
251
-				}
252
-			}
253
-
254
-			if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
255
-				// case: x-x
256
-				if ($ranges[1] >= $fileSize) {
257
-					$ranges[1] = $fileSize - 1;
258
-				}
259
-				$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
260
-				$minOffset = $ranges[1] + 1;
261
-				if ($minOffset >= $fileSize) {
262
-					break;
263
-				}
264
-			} elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
265
-				// case: x-
266
-				$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize - 1, 'size' => $fileSize ];
267
-				break;
268
-			} elseif (is_numeric($ranges[1])) {
269
-				// case: -x
270
-				if ($ranges[1] > $fileSize) {
271
-					$ranges[1] = $fileSize;
272
-				}
273
-				$rangeArray[$ind++] = [ 'from' => $fileSize - $ranges[1], 'to' => $fileSize - 1, 'size' => $fileSize ];
274
-				break;
275
-			}
276
-		}
277
-		return $rangeArray;
278
-	}
279
-
280
-	/**
281
-	 * @param View $view
282
-	 * @param string $name
283
-	 * @param string $dir
284
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
285
-	 */
286
-	private static function getSingleFile($view, $dir, $name, $params) {
287
-		$filename = $dir . '/' . $name;
288
-		$file = null;
289
-
290
-		try {
291
-			$userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
292
-			$file = $userFolder->get($filename);
293
-			if (!$file instanceof \OC\Files\Node\File || !$file->isReadable()) {
294
-				http_response_code(403);
295
-				die('403 Forbidden');
296
-			}
297
-			$fileSize = $file->getSize();
298
-		} catch (\OCP\Files\NotPermittedException $e) {
299
-			http_response_code(403);
300
-			die('403 Forbidden');
301
-		} catch (\OCP\Files\InvalidPathException $e) {
302
-			http_response_code(403);
303
-			die('403 Forbidden');
304
-		} catch (\OCP\Files\NotFoundException $e) {
305
-			http_response_code(404);
306
-			$tmpl = new OC_Template('', '404', 'guest');
307
-			$tmpl->printPage();
308
-			exit();
309
-		}
310
-
311
-		OC_Util::obEnd();
312
-		$view->lockFile($filename, ILockingProvider::LOCK_SHARED);
313
-
314
-		$rangeArray = [];
315
-
316
-		if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
317
-			$rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
318
-		}
319
-
320
-		self::sendHeaders($filename, $name, $rangeArray);
321
-
322
-		if (isset($params['head']) && $params['head']) {
323
-			return;
324
-		}
325
-
326
-		if (!empty($rangeArray)) {
327
-			try {
328
-				if (count($rangeArray) == 1) {
329
-					$view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
330
-				} else {
331
-					// check if file is seekable (if not throw UnseekableException)
332
-					// we have to check it before body contents
333
-					$view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
334
-
335
-					$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
336
-
337
-					foreach ($rangeArray as $range) {
338
-						echo "\r\n--".self::getBoundary()."\r\n".
339
-						 "Content-type: ".$type."\r\n".
340
-						 "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
341
-						$view->readfilePart($filename, $range['from'], $range['to']);
342
-					}
343
-					echo "\r\n--".self::getBoundary()."--\r\n";
344
-				}
345
-			} catch (\OCP\Files\UnseekableException $ex) {
346
-				// file is unseekable
347
-				header_remove('Accept-Ranges');
348
-				header_remove('Content-Range');
349
-				http_response_code(200);
350
-				self::sendHeaders($filename, $name, []);
351
-				$view->readfile($filename);
352
-			}
353
-		} else {
354
-			$view->readfile($filename);
355
-		}
356
-	}
357
-
358
-	/**
359
-	 * Returns the total (recursive) number of files and folders in the given
360
-	 * FileInfos.
361
-	 *
362
-	 * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count
363
-	 * @return int the total number of files and folders
364
-	 */
365
-	private static function getNumberOfFiles($fileInfos) {
366
-		$numberOfFiles = 0;
367
-
368
-		$view = new View();
369
-
370
-		while ($fileInfo = array_pop($fileInfos)) {
371
-			$numberOfFiles++;
372
-
373
-			if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) {
374
-				$fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));
375
-			}
376
-		}
377
-
378
-		return $numberOfFiles;
379
-	}
380
-
381
-	/**
382
-	 * @param View $view
383
-	 * @param string $dir
384
-	 * @param string[]|string $files
385
-	 */
386
-	public static function lockFiles($view, $dir, $files) {
387
-		if (!is_array($files)) {
388
-			$file = $dir . '/' . $files;
389
-			$files = [$file];
390
-		}
391
-		foreach ($files as $file) {
392
-			$file = $dir . '/' . $file;
393
-			$view->lockFile($file, ILockingProvider::LOCK_SHARED);
394
-			if ($view->is_dir($file)) {
395
-				$contents = $view->getDirectoryContent($file);
396
-				$contents = array_map(function ($fileInfo) use ($file) {
397
-					/** @var \OCP\Files\FileInfo $fileInfo */
398
-					return $file . '/' . $fileInfo->getName();
399
-				}, $contents);
400
-				self::lockFiles($view, $dir, $contents);
401
-			}
402
-		}
403
-	}
404
-
405
-	/**
406
-	 * @param string $dir
407
-	 * @param $files
408
-	 * @param integer $getType
409
-	 * @param View $view
410
-	 * @param string $filename
411
-	 */
412
-	private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
413
-		if ($getType === self::FILE) {
414
-			$view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
415
-		}
416
-		if ($getType === self::ZIP_FILES) {
417
-			foreach ($files as $file) {
418
-				$file = $dir . '/' . $file;
419
-				$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
420
-			}
421
-		}
422
-		if ($getType === self::ZIP_DIR) {
423
-			$file = $dir . '/' . $files;
424
-			$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
425
-		}
426
-	}
54
+    public const FILE = 1;
55
+    public const ZIP_FILES = 2;
56
+    public const ZIP_DIR = 3;
57
+
58
+    public const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
59
+
60
+
61
+    private static $multipartBoundary = '';
62
+
63
+    /**
64
+     * @return string
65
+     */
66
+    private static function getBoundary() {
67
+        if (empty(self::$multipartBoundary)) {
68
+            self::$multipartBoundary = md5(mt_rand());
69
+        }
70
+        return self::$multipartBoundary;
71
+    }
72
+
73
+    /**
74
+     * @param string $filename
75
+     * @param string $name
76
+     * @param array $rangeArray ('from'=>int,'to'=>int), ...
77
+     */
78
+    private static function sendHeaders($filename, $name, array $rangeArray) {
79
+        OC_Response::setContentDispositionHeader($name, 'attachment');
80
+        header('Content-Transfer-Encoding: binary', true);
81
+        header('Pragma: public');// enable caching in IE
82
+        header('Expires: 0');
83
+        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
84
+        $fileSize = \OC\Files\Filesystem::filesize($filename);
85
+        $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
86
+        if ($fileSize > -1) {
87
+            if (!empty($rangeArray)) {
88
+                http_response_code(206);
89
+                header('Accept-Ranges: bytes', true);
90
+                if (count($rangeArray) > 1) {
91
+                    $type = 'multipart/byteranges; boundary='.self::getBoundary();
92
+                // no Content-Length header here
93
+                } else {
94
+                    header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
95
+                    OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
96
+                }
97
+            } else {
98
+                OC_Response::setContentLengthHeader($fileSize);
99
+            }
100
+        }
101
+        header('Content-Type: '.$type, true);
102
+    }
103
+
104
+    /**
105
+     * return the content of a file or return a zip file containing multiple files
106
+     *
107
+     * @param string $dir
108
+     * @param string $files ; separated list of files to download
109
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
110
+     */
111
+    public static function get($dir, $files, $params = null) {
112
+        OC_Util::setupFS();
113
+        $view = \OC\Files\Filesystem::getView();
114
+        $getType = self::FILE;
115
+        $filename = $dir;
116
+        try {
117
+            if (is_array($files) && count($files) === 1) {
118
+                $files = $files[0];
119
+            }
120
+
121
+            if (!is_array($files)) {
122
+                $filename = $dir . '/' . $files;
123
+                if (!$view->is_dir($filename)) {
124
+                    self::getSingleFile($view, $dir, $files, is_null($params) ? [] : $params);
125
+                    return;
126
+                }
127
+            }
128
+
129
+            $name = 'download';
130
+            if (is_array($files)) {
131
+                $getType = self::ZIP_FILES;
132
+                $basename = basename($dir);
133
+                if ($basename) {
134
+                    $name = $basename;
135
+                }
136
+
137
+                $filename = $dir . '/' . $name;
138
+            } else {
139
+                $filename = $dir . '/' . $files;
140
+                $getType = self::ZIP_DIR;
141
+                // downloading root ?
142
+                if ($files !== '') {
143
+                    $name = $files;
144
+                }
145
+            }
146
+
147
+            self::lockFiles($view, $dir, $files);
148
+
149
+            /* Calculate filesize and number of files */
150
+            if ($getType === self::ZIP_FILES) {
151
+                $fileInfos = [];
152
+                $fileSize = 0;
153
+                foreach ($files as $file) {
154
+                    $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);
155
+                    $fileSize += $fileInfo->getSize();
156
+                    $fileInfos[] = $fileInfo;
157
+                }
158
+                $numberOfFiles = self::getNumberOfFiles($fileInfos);
159
+            } elseif ($getType === self::ZIP_DIR) {
160
+                $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);
161
+                $fileSize = $fileInfo->getSize();
162
+                $numberOfFiles = self::getNumberOfFiles([$fileInfo]);
163
+            }
164
+
165
+            $streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);
166
+            OC_Util::obEnd();
167
+
168
+            $streamer->sendHeaders($name);
169
+            $executionTime = (int)OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time');
170
+            if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
171
+                @set_time_limit(0);
172
+            }
173
+            ignore_user_abort(true);
174
+
175
+            if ($getType === self::ZIP_FILES) {
176
+                foreach ($files as $file) {
177
+                    $file = $dir . '/' . $file;
178
+                    if (\OC\Files\Filesystem::is_file($file)) {
179
+                        $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
180
+                        $file = $userFolder->get($file);
181
+                        if ($file instanceof \OC\Files\Node\File) {
182
+                            try {
183
+                                $fh = $file->fopen('r');
184
+                            } catch (\OCP\Files\NotPermittedException $e) {
185
+                                continue;
186
+                            }
187
+                            $fileSize = $file->getSize();
188
+                            $fileTime = $file->getMTime();
189
+                        } else {
190
+                            // File is not a file? …
191
+                            \OC::$server->getLogger()->debug(
192
+                                'File given, but no Node available. Name {file}',
193
+                                [ 'app' => 'files', 'file' => $file ]
194
+                            );
195
+                            continue;
196
+                        }
197
+                        $streamer->addFileFromStream($fh, $file->getName(), $fileSize, $fileTime);
198
+                        fclose($fh);
199
+                    } elseif (\OC\Files\Filesystem::is_dir($file)) {
200
+                        $streamer->addDirRecursive($file);
201
+                    }
202
+                }
203
+            } elseif ($getType === self::ZIP_DIR) {
204
+                $file = $dir . '/' . $files;
205
+                $streamer->addDirRecursive($file);
206
+            }
207
+            $streamer->finalize();
208
+            set_time_limit($executionTime);
209
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
210
+        } catch (\OCP\Lock\LockedException $ex) {
211
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
212
+            OC::$server->getLogger()->logException($ex);
213
+            $l = \OC::$server->getL10N('lib');
214
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
215
+            \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
216
+        } catch (\OCP\Files\ForbiddenException $ex) {
217
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
218
+            OC::$server->getLogger()->logException($ex);
219
+            $l = \OC::$server->getL10N('lib');
220
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200);
221
+        } catch (\Exception $ex) {
222
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
223
+            OC::$server->getLogger()->logException($ex);
224
+            $l = \OC::$server->getL10N('lib');
225
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
226
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200);
227
+        }
228
+    }
229
+
230
+    /**
231
+     * @param string $rangeHeaderPos
232
+     * @param int $fileSize
233
+     * @return array $rangeArray ('from'=>int,'to'=>int), ...
234
+     */
235
+    private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
236
+        $rArray = explode(',', $rangeHeaderPos);
237
+        $minOffset = 0;
238
+        $ind = 0;
239
+
240
+        $rangeArray = [];
241
+
242
+        foreach ($rArray as $value) {
243
+            $ranges = explode('-', $value);
244
+            if (is_numeric($ranges[0])) {
245
+                if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
246
+                    $ranges[0] = $minOffset;
247
+                }
248
+                if ($ind > 0 && $rangeArray[$ind - 1]['to'] + 1 == $ranges[0]) { // case: bytes=500-600,601-999
249
+                    $ind--;
250
+                    $ranges[0] = $rangeArray[$ind]['from'];
251
+                }
252
+            }
253
+
254
+            if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
255
+                // case: x-x
256
+                if ($ranges[1] >= $fileSize) {
257
+                    $ranges[1] = $fileSize - 1;
258
+                }
259
+                $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
260
+                $minOffset = $ranges[1] + 1;
261
+                if ($minOffset >= $fileSize) {
262
+                    break;
263
+                }
264
+            } elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
265
+                // case: x-
266
+                $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize - 1, 'size' => $fileSize ];
267
+                break;
268
+            } elseif (is_numeric($ranges[1])) {
269
+                // case: -x
270
+                if ($ranges[1] > $fileSize) {
271
+                    $ranges[1] = $fileSize;
272
+                }
273
+                $rangeArray[$ind++] = [ 'from' => $fileSize - $ranges[1], 'to' => $fileSize - 1, 'size' => $fileSize ];
274
+                break;
275
+            }
276
+        }
277
+        return $rangeArray;
278
+    }
279
+
280
+    /**
281
+     * @param View $view
282
+     * @param string $name
283
+     * @param string $dir
284
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
285
+     */
286
+    private static function getSingleFile($view, $dir, $name, $params) {
287
+        $filename = $dir . '/' . $name;
288
+        $file = null;
289
+
290
+        try {
291
+            $userFolder = \OC::$server->getRootFolder()->get(\OC\Files\Filesystem::getRoot());
292
+            $file = $userFolder->get($filename);
293
+            if (!$file instanceof \OC\Files\Node\File || !$file->isReadable()) {
294
+                http_response_code(403);
295
+                die('403 Forbidden');
296
+            }
297
+            $fileSize = $file->getSize();
298
+        } catch (\OCP\Files\NotPermittedException $e) {
299
+            http_response_code(403);
300
+            die('403 Forbidden');
301
+        } catch (\OCP\Files\InvalidPathException $e) {
302
+            http_response_code(403);
303
+            die('403 Forbidden');
304
+        } catch (\OCP\Files\NotFoundException $e) {
305
+            http_response_code(404);
306
+            $tmpl = new OC_Template('', '404', 'guest');
307
+            $tmpl->printPage();
308
+            exit();
309
+        }
310
+
311
+        OC_Util::obEnd();
312
+        $view->lockFile($filename, ILockingProvider::LOCK_SHARED);
313
+
314
+        $rangeArray = [];
315
+
316
+        if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
317
+            $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), $fileSize);
318
+        }
319
+
320
+        self::sendHeaders($filename, $name, $rangeArray);
321
+
322
+        if (isset($params['head']) && $params['head']) {
323
+            return;
324
+        }
325
+
326
+        if (!empty($rangeArray)) {
327
+            try {
328
+                if (count($rangeArray) == 1) {
329
+                    $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
330
+                } else {
331
+                    // check if file is seekable (if not throw UnseekableException)
332
+                    // we have to check it before body contents
333
+                    $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
334
+
335
+                    $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
336
+
337
+                    foreach ($rangeArray as $range) {
338
+                        echo "\r\n--".self::getBoundary()."\r\n".
339
+                            "Content-type: ".$type."\r\n".
340
+                            "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
341
+                        $view->readfilePart($filename, $range['from'], $range['to']);
342
+                    }
343
+                    echo "\r\n--".self::getBoundary()."--\r\n";
344
+                }
345
+            } catch (\OCP\Files\UnseekableException $ex) {
346
+                // file is unseekable
347
+                header_remove('Accept-Ranges');
348
+                header_remove('Content-Range');
349
+                http_response_code(200);
350
+                self::sendHeaders($filename, $name, []);
351
+                $view->readfile($filename);
352
+            }
353
+        } else {
354
+            $view->readfile($filename);
355
+        }
356
+    }
357
+
358
+    /**
359
+     * Returns the total (recursive) number of files and folders in the given
360
+     * FileInfos.
361
+     *
362
+     * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count
363
+     * @return int the total number of files and folders
364
+     */
365
+    private static function getNumberOfFiles($fileInfos) {
366
+        $numberOfFiles = 0;
367
+
368
+        $view = new View();
369
+
370
+        while ($fileInfo = array_pop($fileInfos)) {
371
+            $numberOfFiles++;
372
+
373
+            if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) {
374
+                $fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));
375
+            }
376
+        }
377
+
378
+        return $numberOfFiles;
379
+    }
380
+
381
+    /**
382
+     * @param View $view
383
+     * @param string $dir
384
+     * @param string[]|string $files
385
+     */
386
+    public static function lockFiles($view, $dir, $files) {
387
+        if (!is_array($files)) {
388
+            $file = $dir . '/' . $files;
389
+            $files = [$file];
390
+        }
391
+        foreach ($files as $file) {
392
+            $file = $dir . '/' . $file;
393
+            $view->lockFile($file, ILockingProvider::LOCK_SHARED);
394
+            if ($view->is_dir($file)) {
395
+                $contents = $view->getDirectoryContent($file);
396
+                $contents = array_map(function ($fileInfo) use ($file) {
397
+                    /** @var \OCP\Files\FileInfo $fileInfo */
398
+                    return $file . '/' . $fileInfo->getName();
399
+                }, $contents);
400
+                self::lockFiles($view, $dir, $contents);
401
+            }
402
+        }
403
+    }
404
+
405
+    /**
406
+     * @param string $dir
407
+     * @param $files
408
+     * @param integer $getType
409
+     * @param View $view
410
+     * @param string $filename
411
+     */
412
+    private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
413
+        if ($getType === self::FILE) {
414
+            $view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
415
+        }
416
+        if ($getType === self::ZIP_FILES) {
417
+            foreach ($files as $file) {
418
+                $file = $dir . '/' . $file;
419
+                $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
420
+            }
421
+        }
422
+        if ($getType === self::ZIP_DIR) {
423
+            $file = $dir . '/' . $files;
424
+            $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
425
+        }
426
+    }
427 427
 }
Please login to merge, or discard this patch.