Completed
Push — stable8 ( 42720e...c45eda )
by
unknown
35s
created

Filesystem   F

Complexity

Total Complexity 118

Size/Duplication

Total Lines 826
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 15

Importance

Changes 0
Metric Value
dl 0
loc 826
rs 1.263
c 0
b 0
f 0
wmc 118
lcom 2
cbo 15

65 Methods

Rating   Name   Duplication   Size   Complexity  
A addStorageWrapper() 0 7 2
A getLoader() 0 6 2
A getMountManager() 0 6 2
A getMountPoint() 0 11 3
A getMountPoints() 0 11 3
A getStorage() 0 7 2
A getMountByStorageId() 0 6 2
A getMountByNumericId() 0 6 2
A resolvePath() 0 11 3
A init() 0 18 3
A initMounts() 0 5 2
C initMountPoints() 0 59 9
A mountCacheDir() 0 18 4
A getView() 0 3 1
A tearDown() 0 4 1
A getRoot() 0 6 2
A clearMounts() 0 6 2
A mount() 0 7 2
A getLocalFile() 0 3 1
A getLocalFolder() 0 3 1
A getLocalPath() 0 8 2
B isValidPath() 0 10 5
B isBlacklisted() 0 12 5
A isFileBlacklisted() 0 7 1
A isIgnoredDir() 0 6 3
A mkdir() 0 3 1
A rmdir() 0 3 1
A opendir() 0 3 1
A readdir() 0 3 1
A is_dir() 0 3 1
A is_file() 0 3 1
A stat() 0 3 1
A filetype() 0 3 1
A filesize() 0 3 1
A readfile() 0 3 1
A isCreatable() 0 3 1
A isReadable() 0 3 1
A isUpdatable() 0 3 1
A isDeletable() 0 3 1
A isSharable() 0 3 1
A file_exists() 0 3 1
A filemtime() 0 3 1
A touch() 0 3 1
A file_get_contents() 0 3 1
A file_put_contents() 0 3 1
A unlink() 0 3 1
A rename() 0 3 1
A copy() 0 3 1
A fopen() 0 3 1
A toTmpFile() 0 3 1
A fromTmpFile() 0 3 1
A getMimeType() 0 3 1
A hash() 0 3 1
A free_space() 0 3 1
A search() 0 3 1
A searchByMime() 0 3 1
A searchByTag() 0 3 1
A hasUpdated() 0 3 1
C normalizePath() 0 63 14
A getFileInfo() 0 3 1
A putFileInfo() 0 3 1
A getDirectoryContent() 0 3 1
A getPath() 0 3 1
A getOwner() 0 3 1
A getETag() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Filesystem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Filesystem, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Copyright (c) 2012 Robin Appelman <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file.
7
 */
8
9
/**
10
 * Class for abstraction of filesystem functions
11
 * This class won't call any filesystem functions for itself but will pass them to the correct OC_Filestorage object
12
 * this class should also handle all the file permission related stuff
13
 *
14
 * Hooks provided:
15
 *   read(path)
16
 *   write(path, &run)
17
 *   post_write(path)
18
 *   create(path, &run) (when a file is created, both create and write will be emitted in that order)
19
 *   post_create(path)
20
 *   delete(path, &run)
21
 *   post_delete(path)
22
 *   rename(oldpath,newpath, &run)
23
 *   post_rename(oldpath,newpath)
24
 *   copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order)
25
 *   post_rename(oldpath,newpath)
26
 *   post_initMountPoints(user, user_dir)
27
 *
28
 *   the &run parameter can be set to false to prevent the operation from occurring
29
 */
30
31
namespace OC\Files;
32
33
use OC\Files\Storage\StorageFactory;
34
35
class Filesystem {
36
37
	/**
38
	 * @var Mount\Manager $mounts
39
	 */
40
	private static $mounts;
41
42
	public static $loaded = false;
43
	/**
44
	 * @var \OC\Files\View $defaultInstance
45
	 */
46
	static private $defaultInstance;
47
48
	static private $usersSetup = array();
49
50
	static private $normalizedPathCache = array();
51
52
	/**
53
	 * classname which used for hooks handling
54
	 * used as signalclass in OC_Hooks::emit()
55
	 */
56
	const CLASSNAME = 'OC_Filesystem';
57
58
	/**
59
	 * signalname emitted before file renaming
60
	 *
61
	 * @param string $oldpath
62
	 * @param string $newpath
63
	 */
64
	const signal_rename = 'rename';
65
66
	/**
67
	 * signal emitted after file renaming
68
	 *
69
	 * @param string $oldpath
70
	 * @param string $newpath
71
	 */
72
	const signal_post_rename = 'post_rename';
73
74
	/**
75
	 * signal emitted before file/dir creation
76
	 *
77
	 * @param string $path
78
	 * @param bool $run changing this flag to false in hook handler will cancel event
79
	 */
80
	const signal_create = 'create';
81
82
	/**
83
	 * signal emitted after file/dir creation
84
	 *
85
	 * @param string $path
86
	 * @param bool $run changing this flag to false in hook handler will cancel event
87
	 */
88
	const signal_post_create = 'post_create';
89
90
	/**
91
	 * signal emits before file/dir copy
92
	 *
93
	 * @param string $oldpath
94
	 * @param string $newpath
95
	 * @param bool $run changing this flag to false in hook handler will cancel event
96
	 */
97
	const signal_copy = 'copy';
98
99
	/**
100
	 * signal emits after file/dir copy
101
	 *
102
	 * @param string $oldpath
103
	 * @param string $newpath
104
	 */
105
	const signal_post_copy = 'post_copy';
106
107
	/**
108
	 * signal emits before file/dir save
109
	 *
110
	 * @param string $path
111
	 * @param bool $run changing this flag to false in hook handler will cancel event
112
	 */
113
	const signal_write = 'write';
114
115
	/**
116
	 * signal emits after file/dir save
117
	 *
118
	 * @param string $path
119
	 */
120
	const signal_post_write = 'post_write';
121
122
	/**
123
	 * signal emitted before file/dir update
124
	 *
125
	 * @param string $path
126
	 * @param bool $run changing this flag to false in hook handler will cancel event
127
	 */
128
	const signal_update = 'update';
129
130
	/**
131
	 * signal emitted after file/dir update
132
	 *
133
	 * @param string $path
134
	 * @param bool $run changing this flag to false in hook handler will cancel event
135
	 */
136
	const signal_post_update = 'post_update';
137
138
	/**
139
	 * signal emits when reading file/dir
140
	 *
141
	 * @param string $path
142
	 */
143
	const signal_read = 'read';
144
145
	/**
146
	 * signal emits when removing file/dir
147
	 *
148
	 * @param string $path
149
	 */
150
	const signal_delete = 'delete';
151
152
	/**
153
	 * parameters definitions for signals
154
	 */
155
	const signal_param_path = 'path';
156
	const signal_param_oldpath = 'oldpath';
157
	const signal_param_newpath = 'newpath';
158
159
	/**
160
	 * run - changing this flag to false in hook handler will cancel event
161
	 */
162
	const signal_param_run = 'run';
163
164
	const signal_create_mount = 'create_mount';
165
	const signal_delete_mount = 'delete_mount';
166
	const signal_param_mount_type = 'mounttype';
167
	const signal_param_users = 'users';
168
169
	/**
170
	 * @var \OC\Files\Storage\StorageFactory $loader
171
	 */
172
	private static $loader;
173
174
	/**
175
	 * @param callable $wrapper
176
	 */
177
	public static function addStorageWrapper($wrapperName, $wrapper) {
178
		$mounts = self::getMountManager()->getAll();
179
		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $mounts)) {
180
			// do not re-wrap if storage with this name already existed
181
			return;
182
		}
183
	}
184
185
	/**
186
	 * Returns the storage factory
187
	 *
188
	 * @return \OCP\Files\Storage\IStorageFactory
189
	 */
190
	public static function getLoader() {
191
		if (!self::$loader) {
192
			self::$loader = new StorageFactory();
193
		}
194
		return self::$loader;
195
	}
196
197
	/**
198
	 * Returns the mount manager
199
	 *
200
	 * @return \OC\Files\Mount\Manager
201
	 */
202
	public static function getMountManager() {
203
		if (!self::$mounts) {
204
			\OC_Util::setupFS();
205
		}
206
		return self::$mounts;
207
	}
208
209
	/**
210
	 * get the mountpoint of the storage object for a path
211
	 * ( note: because a storage is not always mounted inside the fakeroot, the
212
	 * returned mountpoint is relative to the absolute root of the filesystem
213
	 * and doesn't take the chroot into account )
214
	 *
215
	 * @param string $path
216
	 * @return string
217
	 */
218
	static public function getMountPoint($path) {
219
		if (!self::$mounts) {
220
			\OC_Util::setupFS();
221
		}
222
		$mount = self::$mounts->find($path);
223
		if ($mount) {
224
			return $mount->getMountPoint();
225
		} else {
226
			return '';
227
		}
228
	}
229
230
	/**
231
	 * get a list of all mount points in a directory
232
	 *
233
	 * @param string $path
234
	 * @return string[]
235
	 */
236
	static public function getMountPoints($path) {
237
		if (!self::$mounts) {
238
			\OC_Util::setupFS();
239
		}
240
		$result = array();
241
		$mounts = self::$mounts->findIn($path);
242
		foreach ($mounts as $mount) {
243
			$result[] = $mount->getMountPoint();
244
		}
245
		return $result;
246
	}
247
248
	/**
249
	 * get the storage mounted at $mountPoint
250
	 *
251
	 * @param string $mountPoint
252
	 * @return \OC\Files\Storage\Storage
253
	 */
254
	public static function getStorage($mountPoint) {
255
		if (!self::$mounts) {
256
			\OC_Util::setupFS();
257
		}
258
		$mount = self::$mounts->find($mountPoint);
259
		return $mount->getStorage();
260
	}
261
262
	/**
263
	 * @param string $id
264
	 * @return Mount\MountPoint[]
265
	 */
266
	public static function getMountByStorageId($id) {
267
		if (!self::$mounts) {
268
			\OC_Util::setupFS();
269
		}
270
		return self::$mounts->findByStorageId($id);
271
	}
272
273
	/**
274
	 * @param int $id
275
	 * @return Mount\MountPoint[]
276
	 */
277
	public static function getMountByNumericId($id) {
278
		if (!self::$mounts) {
279
			\OC_Util::setupFS();
280
		}
281
		return self::$mounts->findByNumericId($id);
282
	}
283
284
	/**
285
	 * resolve a path to a storage and internal path
286
	 *
287
	 * @param string $path
288
	 * @return array an array consisting of the storage and the internal path
289
	 */
290
	static public function resolvePath($path) {
291
		if (!self::$mounts) {
292
			\OC_Util::setupFS();
293
		}
294
		$mount = self::$mounts->find($path);
295
		if ($mount) {
296
			return array($mount->getStorage(), rtrim($mount->getInternalPath($path), '/'));
297
		} else {
298
			return array(null, null);
299
		}
300
	}
301
302
	static public function init($user, $root) {
303
		if (self::$defaultInstance) {
304
			return false;
305
		}
306
		self::getLoader();
307
		self::$defaultInstance = new View($root);
308
309
		if (!self::$mounts) {
310
			self::$mounts = new Mount\Manager();
311
		}
312
313
		//load custom mount config
314
		self::initMountPoints($user);
315
316
		self::$loaded = true;
317
318
		return true;
319
	}
320
321
	static public function initMounts() {
322
		if (!self::$mounts) {
323
			self::$mounts = new Mount\Manager();
324
		}
325
	}
326
327
	/**
328
	 * Initialize system and personal mount points for a user
329
	 *
330
	 * @param string $user
331
	 */
332
	public static function initMountPoints($user = '') {
333
		if ($user == '') {
334
			$user = \OC_User::getUser();
335
		}
336
		if (isset(self::$usersSetup[$user])) {
337
			return;
338
		}
339
		self::$usersSetup[$user] = true;
340
341
		$root = \OC_User::getHome($user);
342
343
		$userObject = \OC_User::getManager()->get($user);
344
345
		if (is_null($userObject)) {
346
			\OCP\Util::writeLog('files', ' Backends provided no user object for '.$user, \OCP\Util::ERROR);
347
			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
348
		}
349
350
		$homeStorage = \OC_Config::getValue( 'objectstore' );
351
		if (!empty($homeStorage)) {
352
			// sanity checks
353
			if (empty($homeStorage['class'])) {
354
				\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
355
			}
356
			if (!isset($homeStorage['arguments'])) {
357
				$homeStorage['arguments'] = array();
358
			}
359
			// instantiate object store implementation
360
			$homeStorage['arguments']['objectstore'] = new $homeStorage['class']($homeStorage['arguments']);
361
			// mount with home object store implementation
362
			$homeStorage['class'] = '\OC\Files\ObjectStore\HomeObjectStoreStorage';
363
		} else {
364
			$homeStorage = array(
365
				//default home storage configuration:
366
				'class' => '\OC\Files\Storage\Home',
367
				'arguments' => array()
368
			);
369
		}
370
		$homeStorage['arguments']['user'] = $userObject;
371
372
		// check for legacy home id (<= 5.0.12)
373
		if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) {
374
			$homeStorage['arguments']['legacy'] = true;
375
		}
376
377
		self::mount($homeStorage['class'], $homeStorage['arguments'], $user);
378
379
		$home = \OC\Files\Filesystem::getStorage($user);
0 ignored issues
show
Unused Code introduced by
$home is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
380
381
		self::mountCacheDir($user);
382
383
		// Chance to mount for other storages
384
		if($userObject) {
385
			$mountConfigManager = \OC::$server->getMountProviderCollection();
386
			$mounts = $mountConfigManager->getMountsForUser($userObject);
387
			array_walk($mounts, array(self::$mounts, 'addMount'));
388
		}
389
		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
390
	}
391
392
	/**
393
	 * Mounts the cache directory
394
	 * @param string $user user name
395
	 */
396
	private static function mountCacheDir($user) {
397
		$cacheBaseDir = \OC_Config::getValue('cache_path', '');
398
		if ($cacheBaseDir === '') {
399
			// use local cache dir relative to the user's home
400
			$subdir = 'cache';
401
			$view = new \OC\Files\View('/' . $user);
402
			if(!$view->file_exists($subdir)) {
403
				$view->mkdir($subdir);
404
			}
405
		} else {
406
			$cacheDir = rtrim($cacheBaseDir, '/') . '/' . $user;
407
			if (!file_exists($cacheDir)) {
408
				mkdir($cacheDir, 0770, true);
409
			}
410
			// mount external cache dir to "/$user/cache" mount point
411
			self::mount('\OC\Files\Storage\Local', array('datadir' => $cacheDir), '/' . $user . '/cache');
412
		}
413
	}
414
415
	/**
416
	 * get the default filesystem view
417
	 *
418
	 * @return View
419
	 */
420
	static public function getView() {
421
		return self::$defaultInstance;
422
	}
423
424
	/**
425
	 * tear down the filesystem, removing all storage providers
426
	 */
427
	static public function tearDown() {
428
		self::clearMounts();
429
		self::$defaultInstance = null;
430
	}
431
432
	/**
433
	 * get the relative path of the root data directory for the current user
434
	 * @return string
435
	 *
436
	 * Returns path like /admin/files
437
	 */
438
	static public function getRoot() {
439
		if (!self::$defaultInstance) {
440
			return null;
441
		}
442
		return self::$defaultInstance->getRoot();
443
	}
444
445
	/**
446
	 * clear all mounts and storage backends
447
	 */
448
	public static function clearMounts() {
449
		if (self::$mounts) {
450
			self::$usersSetup = array();
451
			self::$mounts->clear();
452
		}
453
	}
454
455
	/**
456
	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
457
	 *
458
	 * @param \OC\Files\Storage\Storage|string $class
459
	 * @param array $arguments
460
	 * @param string $mountpoint
461
	 */
462
	static public function mount($class, $arguments, $mountpoint) {
463
		if (!self::$mounts) {
464
			\OC_Util::setupFS();
465
		}
466
		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
467
		self::$mounts->addMount($mount);
468
	}
469
470
	/**
471
	 * return the path to a local version of the file
472
	 * we need this because we can't know if a file is stored local or not from
473
	 * outside the filestorage and for some purposes a local file is needed
474
	 *
475
	 * @param string $path
476
	 * @return string
477
	 */
478
	static public function getLocalFile($path) {
479
		return self::$defaultInstance->getLocalFile($path);
480
	}
481
482
	/**
483
	 * @param string $path
484
	 * @return string
485
	 */
486
	static public function getLocalFolder($path) {
487
		return self::$defaultInstance->getLocalFolder($path);
488
	}
489
490
	/**
491
	 * return path to file which reflects one visible in browser
492
	 *
493
	 * @param string $path
494
	 * @return string
495
	 */
496
	static public function getLocalPath($path) {
497
		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
498
		$newpath = $path;
499
		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
500
			$newpath = substr($path, strlen($datadir));
501
		}
502
		return $newpath;
503
	}
504
505
	/**
506
	 * check if the requested path is valid
507
	 *
508
	 * @param string $path
509
	 * @return bool
510
	 */
511
	static public function isValidPath($path) {
512
		$path = self::normalizePath($path);
513
		if (!$path || $path[0] !== '/') {
514
			$path = '/' . $path;
515
		}
516
		if (strpos($path, '/../') !== FALSE || strrchr($path, '/') === '/..') {
517
			return false;
518
		}
519
		return true;
520
	}
521
522
	/**
523
	 * checks if a file is blacklisted for storage in the filesystem
524
	 * Listens to write and rename hooks
525
	 *
526
	 * @param array $data from hook
527
	 */
528
	static public function isBlacklisted($data) {
529
		if (isset($data['path'])) {
530
			$path = $data['path'];
531
		} else if (isset($data['newpath'])) {
532
			$path = $data['newpath'];
533
		}
534
		if (isset($path)) {
535
			if (self::isFileBlacklisted($path)) {
536
				$data['run'] = false;
537
			}
538
		}
539
	}
540
541
	/**
542
	 * @param string $filename
543
	 * @return bool
544
	 */
545
	static public function isFileBlacklisted($filename) {
546
		$filename = self::normalizePath($filename);
547
548
		$blacklist = \OC_Config::getValue('blacklisted_files', array('.htaccess'));
549
		$filename = strtolower(basename($filename));
550
		return in_array($filename, $blacklist);
551
	}
552
553
	/**
554
	 * check if the directory should be ignored when scanning
555
	 * NOTE: the special directories . and .. would cause never ending recursion
556
	 * @param String $dir
557
	 * @return boolean
558
	 */
559
	static public function isIgnoredDir($dir) {
560
		if ($dir === '.' || $dir === '..') {
561
			return true;
562
		}
563
		return false;
564
	}
565
566
	/**
567
	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
568
	 */
569
	static public function mkdir($path) {
570
		return self::$defaultInstance->mkdir($path);
571
	}
572
573
	static public function rmdir($path) {
574
		return self::$defaultInstance->rmdir($path);
575
	}
576
577
	static public function opendir($path) {
578
		return self::$defaultInstance->opendir($path);
579
	}
580
581
	static public function readdir($path) {
582
		return self::$defaultInstance->readdir($path);
583
	}
584
585
	static public function is_dir($path) {
586
		return self::$defaultInstance->is_dir($path);
587
	}
588
589
	static public function is_file($path) {
590
		return self::$defaultInstance->is_file($path);
591
	}
592
593
	static public function stat($path) {
594
		return self::$defaultInstance->stat($path);
595
	}
596
597
	static public function filetype($path) {
598
		return self::$defaultInstance->filetype($path);
599
	}
600
601
	static public function filesize($path) {
602
		return self::$defaultInstance->filesize($path);
603
	}
604
605
	static public function readfile($path) {
606
		return self::$defaultInstance->readfile($path);
607
	}
608
609
	static public function isCreatable($path) {
610
		return self::$defaultInstance->isCreatable($path);
611
	}
612
613
	static public function isReadable($path) {
614
		return self::$defaultInstance->isReadable($path);
615
	}
616
617
	static public function isUpdatable($path) {
618
		return self::$defaultInstance->isUpdatable($path);
619
	}
620
621
	static public function isDeletable($path) {
622
		return self::$defaultInstance->isDeletable($path);
623
	}
624
625
	static public function isSharable($path) {
626
		return self::$defaultInstance->isSharable($path);
627
	}
628
629
	static public function file_exists($path) {
630
		return self::$defaultInstance->file_exists($path);
631
	}
632
633
	static public function filemtime($path) {
634
		return self::$defaultInstance->filemtime($path);
635
	}
636
637
	static public function touch($path, $mtime = null) {
638
		return self::$defaultInstance->touch($path, $mtime);
639
	}
640
641
	/**
642
	 * @return string
643
	 */
644
	static public function file_get_contents($path) {
645
		return self::$defaultInstance->file_get_contents($path);
646
	}
647
648
	static public function file_put_contents($path, $data) {
649
		return self::$defaultInstance->file_put_contents($path, $data);
650
	}
651
652
	static public function unlink($path) {
653
		return self::$defaultInstance->unlink($path);
654
	}
655
656
	static public function rename($path1, $path2) {
657
		return self::$defaultInstance->rename($path1, $path2);
658
	}
659
660
	static public function copy($path1, $path2) {
661
		return self::$defaultInstance->copy($path1, $path2);
662
	}
663
664
	static public function fopen($path, $mode) {
665
		return self::$defaultInstance->fopen($path, $mode);
666
	}
667
668
	/**
669
	 * @return string
670
	 */
671
	static public function toTmpFile($path) {
672
		return self::$defaultInstance->toTmpFile($path);
673
	}
674
675
	static public function fromTmpFile($tmpFile, $path) {
676
		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
677
	}
678
679
	static public function getMimeType($path) {
680
		return self::$defaultInstance->getMimeType($path);
681
	}
682
683
	static public function hash($type, $path, $raw = false) {
684
		return self::$defaultInstance->hash($type, $path, $raw);
685
	}
686
687
	static public function free_space($path = '/') {
688
		return self::$defaultInstance->free_space($path);
689
	}
690
691
	static public function search($query) {
692
		return self::$defaultInstance->search($query);
693
	}
694
695
	/**
696
	 * @param string $query
697
	 */
698
	static public function searchByMime($query) {
699
		return self::$defaultInstance->searchByMime($query);
700
	}
701
702
	/**
703
	 * @param string|int $tag name or tag id
704
	 * @param string $userId owner of the tags
705
	 * @return FileInfo[] array or file info
706
	 */
707
	static public function searchByTag($tag, $userId) {
708
		return self::$defaultInstance->searchByTag($tag, $userId);
709
	}
710
711
	/**
712
	 * check if a file or folder has been updated since $time
713
	 *
714
	 * @param string $path
715
	 * @param int $time
716
	 * @return bool
717
	 */
718
	static public function hasUpdated($path, $time) {
719
		return self::$defaultInstance->hasUpdated($path, $time);
720
	}
721
722
	/**
723
	 * Fix common problems with a file path
724
	 * @param string $path
725
	 * @param bool $stripTrailingSlash
726
	 * @param bool $isAbsolutePath
727
	 * @return string
728
	 */
729
	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false) {
730
		/**
731
		 * FIXME: This is a workaround for existing classes and files which call
732
		 *        this function with another type than a valid string. This
733
		 *        conversion should get removed as soon as all existing
734
		 *        function calls have been fixed.
735
		 */
736
		$path = (string)$path;
737
738
		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath]);
739
740
		if(isset(self::$normalizedPathCache[$cacheKey])) {
741
			return self::$normalizedPathCache[$cacheKey];
742
		}
743
744
		if ($path == '') {
745
			return '/';
746
		}
747
748
		//normalize unicode if possible
749
		$path = \OC_Util::normalizeUnicode($path);
750
751
		//no windows style slashes
752
		$path = str_replace('\\', '/', $path);
753
754
		// When normalizing an absolute path, we need to ensure that the drive-letter
755
		// is still at the beginning on windows
756
		$windows_drive_letter = '';
757
		if ($isAbsolutePath && \OC_Util::runningOnWindows() && preg_match('#^([a-zA-Z])$#', $path[0]) && $path[1] == ':' && $path[2] == '/') {
758
			$windows_drive_letter = substr($path, 0, 2);
759
			$path = substr($path, 2);
760
		}
761
762
		//add leading slash
763
		if ($path[0] !== '/') {
764
			$path = '/' . $path;
765
		}
766
767
		// remove '/./'
768
		// ugly, but str_replace() can't replace them all in one go
769
		// as the replacement itself is part of the search string
770
		// which will only be found during the next iteration
771
		while (strpos($path, '/./') !== false) {
772
			$path = str_replace('/./', '/', $path);
773
		}
774
		// remove sequences of slashes
775
		$path = preg_replace('#/{2,}#', '/', $path);
776
777
		//remove trailing slash
778
		if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') {
779
			$path = substr($path, 0, -1);
780
		}
781
782
		// remove trailing '/.'
783
		if (substr($path, -2) == '/.') {
784
			$path = substr($path, 0, -2);
785
		}
786
787
		$normalizedPath = $windows_drive_letter . $path;
788
		self::$normalizedPathCache[$cacheKey] = $normalizedPath;
789
790
		return $normalizedPath;
791
	}
792
793
	/**
794
	 * get the filesystem info
795
	 *
796
	 * @param string $path
797
	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
798
	 * defaults to true
799
	 * @return \OC\Files\FileInfo
800
	 */
801
	public static function getFileInfo($path, $includeMountPoints = true) {
802
		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::$defaultIns..., $includeMountPoints); (array|OC\Files\FileInfo|false) is incompatible with the return type documented by OC\Files\Filesystem::getFileInfo of type OC\Files\FileInfo.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
803
	}
804
805
	/**
806
	 * change file metadata
807
	 *
808
	 * @param string $path
809
	 * @param array $data
810
	 * @return int
811
	 *
812
	 * returns the fileid of the updated file
813
	 */
814
	public static function putFileInfo($path, $data) {
815
		return self::$defaultInstance->putFileInfo($path, $data);
816
	}
817
818
	/**
819
	 * get the content of a directory
820
	 *
821
	 * @param string $directory path under datadirectory
822
	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
823
	 * @return \OC\Files\FileInfo[]
824
	 */
825
	public static function getDirectoryContent($directory, $mimetype_filter = '') {
826
		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
827
	}
828
829
	/**
830
	 * Get the path of a file by id
831
	 *
832
	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
833
	 *
834
	 * @param int $id
835
	 * @return string
836
	 */
837
	public static function getPath($id) {
838
		return self::$defaultInstance->getPath($id);
839
	}
840
841
	/**
842
	 * Get the owner for a file or folder
843
	 *
844
	 * @param string $path
845
	 * @return string
846
	 */
847
	public static function getOwner($path) {
848
		return self::$defaultInstance->getOwner($path);
849
	}
850
851
	/**
852
	 * get the ETag for a file or folder
853
	 *
854
	 * @param string $path
855
	 * @return string
856
	 */
857
	static public function getETag($path) {
858
		return self::$defaultInstance->getETag($path);
859
	}
860
}
861