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