Completed
Pull Request — master (#4357)
by Johannes
13:27
created
lib/private/legacy/helper.php 1 patch
Indentation   +602 added lines, -602 removed lines patch added patch discarded remove patch
@@ -48,606 +48,606 @@
 block discarded – undo
48 48
  * Collection of useful functions
49 49
  */
50 50
 class OC_Helper {
51
-	private static $templateManager;
52
-
53
-	/**
54
-	 * Creates an absolute url for public use
55
-	 * @param string $service id
56
-	 * @param bool $add_slash
57
-	 * @return string the url
58
-	 *
59
-	 * Returns a absolute url to the given service.
60
-	 */
61
-	public static function linkToPublic($service, $add_slash = false) {
62
-		if ($service === 'files') {
63
-			$url = OC::$server->getURLGenerator()->getAbsoluteURL('/s');
64
-		} else {
65
-			$url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service);
66
-		}
67
-		return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '');
68
-	}
69
-
70
-	/**
71
-	 * Make a human file size
72
-	 * @param int $bytes file size in bytes
73
-	 * @return string a human readable file size
74
-	 *
75
-	 * Makes 2048 to 2 kB.
76
-	 */
77
-	public static function humanFileSize($bytes) {
78
-		if ($bytes < 0) {
79
-			return "?";
80
-		}
81
-		if ($bytes < 1024) {
82
-			return "$bytes B";
83
-		}
84
-		$bytes = round($bytes / 1024, 0);
85
-		if ($bytes < 1024) {
86
-			return "$bytes KB";
87
-		}
88
-		$bytes = round($bytes / 1024, 1);
89
-		if ($bytes < 1024) {
90
-			return "$bytes MB";
91
-		}
92
-		$bytes = round($bytes / 1024, 1);
93
-		if ($bytes < 1024) {
94
-			return "$bytes GB";
95
-		}
96
-		$bytes = round($bytes / 1024, 1);
97
-		if ($bytes < 1024) {
98
-			return "$bytes TB";
99
-		}
100
-
101
-		$bytes = round($bytes / 1024, 1);
102
-		return "$bytes PB";
103
-	}
104
-
105
-	/**
106
-	 * Make a php file size
107
-	 * @param int $bytes file size in bytes
108
-	 * @return string a php parseable file size
109
-	 *
110
-	 * Makes 2048 to 2k and 2^41 to 2048G
111
-	 */
112
-	public static function phpFileSize($bytes) {
113
-		if ($bytes < 0) {
114
-			return "?";
115
-		}
116
-		if ($bytes < 1024) {
117
-			return $bytes . "B";
118
-		}
119
-		$bytes = round($bytes / 1024, 1);
120
-		if ($bytes < 1024) {
121
-			return $bytes . "K";
122
-		}
123
-		$bytes = round($bytes / 1024, 1);
124
-		if ($bytes < 1024) {
125
-			return $bytes . "M";
126
-		}
127
-		$bytes = round($bytes / 1024, 1);
128
-		return $bytes . "G";
129
-	}
130
-
131
-	/**
132
-	 * Make a computer file size
133
-	 * @param string $str file size in human readable format
134
-	 * @return float a file size in bytes
135
-	 *
136
-	 * Makes 2kB to 2048.
137
-	 *
138
-	 * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
139
-	 */
140
-	public static function computerFileSize($str) {
141
-		$str = strtolower($str);
142
-		if (is_numeric($str)) {
143
-			return floatval($str);
144
-		}
145
-
146
-		$bytes_array = array(
147
-			'b' => 1,
148
-			'k' => 1024,
149
-			'kb' => 1024,
150
-			'mb' => 1024 * 1024,
151
-			'm' => 1024 * 1024,
152
-			'gb' => 1024 * 1024 * 1024,
153
-			'g' => 1024 * 1024 * 1024,
154
-			'tb' => 1024 * 1024 * 1024 * 1024,
155
-			't' => 1024 * 1024 * 1024 * 1024,
156
-			'pb' => 1024 * 1024 * 1024 * 1024 * 1024,
157
-			'p' => 1024 * 1024 * 1024 * 1024 * 1024,
158
-		);
159
-
160
-		$bytes = floatval($str);
161
-
162
-		if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) {
163
-			$bytes *= $bytes_array[$matches[1]];
164
-		} else {
165
-			return false;
166
-		}
167
-
168
-		$bytes = round($bytes);
169
-
170
-		return $bytes;
171
-	}
172
-
173
-	/**
174
-	 * Recursive copying of folders
175
-	 * @param string $src source folder
176
-	 * @param string $dest target folder
177
-	 *
178
-	 */
179
-	static function copyr($src, $dest) {
180
-		if (is_dir($src)) {
181
-			if (!is_dir($dest)) {
182
-				mkdir($dest);
183
-			}
184
-			$files = scandir($src);
185
-			foreach ($files as $file) {
186
-				if ($file != "." && $file != "..") {
187
-					self::copyr("$src/$file", "$dest/$file");
188
-				}
189
-			}
190
-		} elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) {
191
-			copy($src, $dest);
192
-		}
193
-	}
194
-
195
-	/**
196
-	 * Recursive deletion of folders
197
-	 * @param string $dir path to the folder
198
-	 * @param bool $deleteSelf if set to false only the content of the folder will be deleted
199
-	 * @return bool
200
-	 */
201
-	static function rmdirr($dir, $deleteSelf = true) {
202
-		if (is_dir($dir)) {
203
-			$files = new RecursiveIteratorIterator(
204
-				new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
205
-				RecursiveIteratorIterator::CHILD_FIRST
206
-			);
207
-
208
-			foreach ($files as $fileInfo) {
209
-				/** @var SplFileInfo $fileInfo */
210
-				if ($fileInfo->isLink()) {
211
-					unlink($fileInfo->getPathname());
212
-				} else if ($fileInfo->isDir()) {
213
-					rmdir($fileInfo->getRealPath());
214
-				} else {
215
-					unlink($fileInfo->getRealPath());
216
-				}
217
-			}
218
-			if ($deleteSelf) {
219
-				rmdir($dir);
220
-			}
221
-		} elseif (file_exists($dir)) {
222
-			if ($deleteSelf) {
223
-				unlink($dir);
224
-			}
225
-		}
226
-		if (!$deleteSelf) {
227
-			return true;
228
-		}
229
-
230
-		return !file_exists($dir);
231
-	}
232
-
233
-	/**
234
-	 * @return \OC\Files\Type\TemplateManager
235
-	 */
236
-	static public function getFileTemplateManager() {
237
-		if (!self::$templateManager) {
238
-			self::$templateManager = new \OC\Files\Type\TemplateManager();
239
-		}
240
-		return self::$templateManager;
241
-	}
242
-
243
-	/**
244
-	 * detect if a given program is found in the search PATH
245
-	 *
246
-	 * @param string $name
247
-	 * @param bool $path
248
-	 * @internal param string $program name
249
-	 * @internal param string $optional search path, defaults to $PATH
250
-	 * @return bool    true if executable program found in path
251
-	 */
252
-	public static function canExecute($name, $path = false) {
253
-		// path defaults to PATH from environment if not set
254
-		if ($path === false) {
255
-			$path = getenv("PATH");
256
-		}
257
-		// we look for an executable file of that name
258
-		$exts = [""];
259
-		$check_fn = "is_executable";
260
-		// Default check will be done with $path directories :
261
-		$dirs = explode(PATH_SEPARATOR, $path);
262
-		// WARNING : We have to check if open_basedir is enabled :
263
-		$obd = OC::$server->getIniWrapper()->getString('open_basedir');
264
-		if ($obd != "none") {
265
-			$obd_values = explode(PATH_SEPARATOR, $obd);
266
-			if (count($obd_values) > 0 and $obd_values[0]) {
267
-				// open_basedir is in effect !
268
-				// We need to check if the program is in one of these dirs :
269
-				$dirs = $obd_values;
270
-			}
271
-		}
272
-		foreach ($dirs as $dir) {
273
-			foreach ($exts as $ext) {
274
-				if ($check_fn("$dir/$name" . $ext))
275
-					return true;
276
-			}
277
-		}
278
-		return false;
279
-	}
280
-
281
-	/**
282
-	 * copy the contents of one stream to another
283
-	 *
284
-	 * @param resource $source
285
-	 * @param resource $target
286
-	 * @return array the number of bytes copied and result
287
-	 */
288
-	public static function streamCopy($source, $target) {
289
-		if (!$source or !$target) {
290
-			return array(0, false);
291
-		}
292
-		$bufSize = 8192;
293
-		$result = true;
294
-		$count = 0;
295
-		while (!feof($source)) {
296
-			$buf = fread($source, $bufSize);
297
-			$bytesWritten = fwrite($target, $buf);
298
-			if ($bytesWritten !== false) {
299
-				$count += $bytesWritten;
300
-			}
301
-			// note: strlen is expensive so only use it when necessary,
302
-			// on the last block
303
-			if ($bytesWritten === false
304
-				|| ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
305
-			) {
306
-				// write error, could be disk full ?
307
-				$result = false;
308
-				break;
309
-			}
310
-		}
311
-		return array($count, $result);
312
-	}
313
-
314
-	/**
315
-	 * Adds a suffix to the name in case the file exists
316
-	 *
317
-	 * @param string $path
318
-	 * @param string $filename
319
-	 * @return string
320
-	 */
321
-	public static function buildNotExistingFileName($path, $filename) {
322
-		$view = \OC\Files\Filesystem::getView();
323
-		return self::buildNotExistingFileNameForView($path, $filename, $view);
324
-	}
325
-
326
-	/**
327
-	 * Adds a suffix to the name in case the file exists
328
-	 *
329
-	 * @param string $path
330
-	 * @param string $filename
331
-	 * @return string
332
-	 */
333
-	public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) {
334
-		if ($path === '/') {
335
-			$path = '';
336
-		}
337
-		if ($pos = strrpos($filename, '.')) {
338
-			$name = substr($filename, 0, $pos);
339
-			$ext = substr($filename, $pos);
340
-		} else {
341
-			$name = $filename;
342
-			$ext = '';
343
-		}
344
-
345
-		$newpath = $path . '/' . $filename;
346
-		if ($view->file_exists($newpath)) {
347
-			if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) {
348
-				//Replace the last "(number)" with "(number+1)"
349
-				$last_match = count($matches[0]) - 1;
350
-				$counter = $matches[1][$last_match][0] + 1;
351
-				$offset = $matches[0][$last_match][1];
352
-				$match_length = strlen($matches[0][$last_match][0]);
353
-			} else {
354
-				$counter = 2;
355
-				$match_length = 0;
356
-				$offset = false;
357
-			}
358
-			do {
359
-				if ($offset) {
360
-					//Replace the last "(number)" with "(number+1)"
361
-					$newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length);
362
-				} else {
363
-					$newname = $name . ' (' . $counter . ')';
364
-				}
365
-				$newpath = $path . '/' . $newname . $ext;
366
-				$counter++;
367
-			} while ($view->file_exists($newpath));
368
-		}
369
-
370
-		return $newpath;
371
-	}
372
-
373
-	/**
374
-	 * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
375
-	 *
376
-	 * @param array $input The array to work on
377
-	 * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
378
-	 * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
379
-	 * @return array
380
-	 *
381
-	 * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
382
-	 * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715
383
-	 *
384
-	 */
385
-	public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
386
-		$case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER;
387
-		$ret = array();
388
-		foreach ($input as $k => $v) {
389
-			$ret[mb_convert_case($k, $case, $encoding)] = $v;
390
-		}
391
-		return $ret;
392
-	}
393
-
394
-	/**
395
-	 * performs a search in a nested array
396
-	 * @param array $haystack the array to be searched
397
-	 * @param string $needle the search string
398
-	 * @param string $index optional, only search this key name
399
-	 * @return mixed the key of the matching field, otherwise false
400
-	 *
401
-	 * performs a search in a nested array
402
-	 *
403
-	 * taken from http://www.php.net/manual/en/function.array-search.php#97645
404
-	 */
405
-	public static function recursiveArraySearch($haystack, $needle, $index = null) {
406
-		$aIt = new RecursiveArrayIterator($haystack);
407
-		$it = new RecursiveIteratorIterator($aIt);
408
-
409
-		while ($it->valid()) {
410
-			if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) {
411
-				return $aIt->key();
412
-			}
413
-
414
-			$it->next();
415
-		}
416
-
417
-		return false;
418
-	}
419
-
420
-	/**
421
-	 * calculates the maximum upload size respecting system settings, free space and user quota
422
-	 *
423
-	 * @param string $dir the current folder where the user currently operates
424
-	 * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
425
-	 * @return int number of bytes representing
426
-	 */
427
-	public static function maxUploadFilesize($dir, $freeSpace = null) {
428
-		if (is_null($freeSpace) || $freeSpace < 0){
429
-			$freeSpace = self::freeSpace($dir);
430
-		}
431
-		return min($freeSpace, self::uploadLimit());
432
-	}
433
-
434
-	/**
435
-	 * Calculate free space left within user quota
436
-	 *
437
-	 * @param string $dir the current folder where the user currently operates
438
-	 * @return int number of bytes representing
439
-	 */
440
-	public static function freeSpace($dir) {
441
-		$freeSpace = \OC\Files\Filesystem::free_space($dir);
442
-		if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
443
-			$freeSpace = max($freeSpace, 0);
444
-			return $freeSpace;
445
-		} else {
446
-			return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
447
-		}
448
-	}
449
-
450
-	/**
451
-	 * Calculate PHP upload limit
452
-	 *
453
-	 * @return int PHP upload file size limit
454
-	 */
455
-	public static function uploadLimit() {
456
-		$ini = \OC::$server->getIniWrapper();
457
-		$upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
458
-		$post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
459
-		if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
460
-			return INF;
461
-		} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
462
-			return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
463
-		} else {
464
-			return min($upload_max_filesize, $post_max_size);
465
-		}
466
-	}
467
-
468
-	/**
469
-	 * Checks if a function is available
470
-	 *
471
-	 * @param string $function_name
472
-	 * @return bool
473
-	 */
474
-	public static function is_function_enabled($function_name) {
475
-		if (!function_exists($function_name)) {
476
-			return false;
477
-		}
478
-		$ini = \OC::$server->getIniWrapper();
479
-		$disabled = explode(',', $ini->get('disable_functions'));
480
-		$disabled = array_map('trim', $disabled);
481
-		if (in_array($function_name, $disabled)) {
482
-			return false;
483
-		}
484
-		$disabled = explode(',', $ini->get('suhosin.executor.func.blacklist'));
485
-		$disabled = array_map('trim', $disabled);
486
-		if (in_array($function_name, $disabled)) {
487
-			return false;
488
-		}
489
-		return true;
490
-	}
491
-
492
-	/**
493
-	 * Try to find a program
494
-	 *
495
-	 * @param string $program
496
-	 * @return null|string
497
-	 */
498
-	public static function findBinaryPath($program) {
499
-		$memcache = \OC::$server->getMemCacheFactory()->create('findBinaryPath');
500
-		if ($memcache->hasKey($program)) {
501
-			return $memcache->get($program);
502
-		}
503
-		$result = null;
504
-		if (self::is_function_enabled('exec')) {
505
-			$exeSniffer = new ExecutableFinder();
506
-			// Returns null if nothing is found
507
-			$result = $exeSniffer->find($program);
508
-			if (empty($result)) {
509
-				$paths = getenv('PATH');
510
-				if (empty($paths)) {
511
-					$paths = '/usr/local/bin /usr/bin /opt/bin /bin';
512
-				} else {
513
-					$paths = str_replace(':',' ',getenv('PATH'));
514
-				}
515
-				$command = 'find ' . $paths . ' -name ' . escapeshellarg($program) . ' 2> /dev/null';
516
-				exec($command, $output, $returnCode);
517
-				if (count($output) > 0) {
518
-					$result = escapeshellcmd($output[0]);
519
-				}
520
-			}
521
-		}
522
-		// store the value for 5 minutes
523
-		$memcache->set($program, $result, 300);
524
-		return $result;
525
-	}
526
-
527
-	/**
528
-	 * Calculate the disc space for the given path
529
-	 *
530
-	 * @param string $path
531
-	 * @param \OCP\Files\FileInfo $rootInfo (optional)
532
-	 * @return array
533
-	 * @throws \OCP\Files\NotFoundException
534
-	 */
535
-	public static function getStorageInfo($path, $rootInfo = null) {
536
-		// return storage info without adding mount points
537
-		$includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
538
-
539
-		if (!$rootInfo) {
540
-			$rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage);
541
-		}
542
-		if (!$rootInfo instanceof \OCP\Files\FileInfo) {
543
-			throw new \OCP\Files\NotFoundException();
544
-		}
545
-		$used = $rootInfo->getSize();
546
-		if ($used < 0) {
547
-			$used = 0;
548
-		}
549
-		$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
550
-		$storage = $rootInfo->getStorage();
551
-		$sourceStorage = $storage;
552
-		if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
553
-			$includeExtStorage = false;
554
-			$sourceStorage = $storage->getSourceStorage();
555
-		}
556
-		if ($includeExtStorage) {
557
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
558
-				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
559
-			) {
560
-				/** @var \OC\Files\Storage\Home $storage */
561
-				$user = $storage->getUser();
562
-			} else {
563
-				$user = \OC::$server->getUserSession()->getUser()->getUID();
564
-			}
565
-			if ($user) {
566
-				$quota = OC_Util::getUserQuota($user);
567
-			} else {
568
-				$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
569
-			}
570
-			if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
571
-				// always get free space / total space from root + mount points
572
-				return self::getGlobalStorageInfo();
573
-			}
574
-		}
575
-
576
-		// TODO: need a better way to get total space from storage
577
-		if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
578
-			/** @var \OC\Files\Storage\Wrapper\Quota $storage */
579
-			$quota = $sourceStorage->getQuota();
580
-		}
581
-		$free = $sourceStorage->free_space($rootInfo->getInternalPath());
582
-		if ($free >= 0) {
583
-			$total = $free + $used;
584
-		} else {
585
-			$total = $free; //either unknown or unlimited
586
-		}
587
-		if ($total > 0) {
588
-			if ($quota > 0 && $total > $quota) {
589
-				$total = $quota;
590
-			}
591
-			// prevent division by zero or error codes (negative values)
592
-			$relative = round(($used / $total) * 10000) / 100;
593
-		} else {
594
-			$relative = 0;
595
-		}
596
-
597
-		$ownerId = $storage->getOwner($path);
598
-		$ownerDisplayName = '';
599
-		$owner = \OC::$server->getUserManager()->get($ownerId);
600
-		if($owner) {
601
-			$ownerDisplayName = $owner->getDisplayName();
602
-		}
603
-
604
-		return [
605
-			'free' => $free,
606
-			'used' => $used,
607
-			'quota' => $quota,
608
-			'total' => $total,
609
-			'relative' => $relative,
610
-			'owner' => $ownerId,
611
-			'ownerDisplayName' => $ownerDisplayName,
612
-		];
613
-	}
614
-
615
-	/**
616
-	 * Get storage info including all mount points and quota
617
-	 *
618
-	 * @return array
619
-	 */
620
-	private static function getGlobalStorageInfo() {
621
-		$quota = OC_Util::getUserQuota(\OCP\User::getUser());
622
-
623
-		$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
624
-		$used = $rootInfo['size'];
625
-		if ($used < 0) {
626
-			$used = 0;
627
-		}
628
-
629
-		$total = $quota;
630
-		$free = $quota - $used;
631
-
632
-		if ($total > 0) {
633
-			if ($quota > 0 && $total > $quota) {
634
-				$total = $quota;
635
-			}
636
-			// prevent division by zero or error codes (negative values)
637
-			$relative = round(($used / $total) * 10000) / 100;
638
-		} else {
639
-			$relative = 0;
640
-		}
641
-
642
-		return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
643
-
644
-	}
645
-
646
-	/**
647
-	 * Returns whether the config file is set manually to read-only
648
-	 * @return bool
649
-	 */
650
-	public static function isReadOnlyConfigEnabled() {
651
-		return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
652
-	}
51
+    private static $templateManager;
52
+
53
+    /**
54
+     * Creates an absolute url for public use
55
+     * @param string $service id
56
+     * @param bool $add_slash
57
+     * @return string the url
58
+     *
59
+     * Returns a absolute url to the given service.
60
+     */
61
+    public static function linkToPublic($service, $add_slash = false) {
62
+        if ($service === 'files') {
63
+            $url = OC::$server->getURLGenerator()->getAbsoluteURL('/s');
64
+        } else {
65
+            $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service);
66
+        }
67
+        return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '');
68
+    }
69
+
70
+    /**
71
+     * Make a human file size
72
+     * @param int $bytes file size in bytes
73
+     * @return string a human readable file size
74
+     *
75
+     * Makes 2048 to 2 kB.
76
+     */
77
+    public static function humanFileSize($bytes) {
78
+        if ($bytes < 0) {
79
+            return "?";
80
+        }
81
+        if ($bytes < 1024) {
82
+            return "$bytes B";
83
+        }
84
+        $bytes = round($bytes / 1024, 0);
85
+        if ($bytes < 1024) {
86
+            return "$bytes KB";
87
+        }
88
+        $bytes = round($bytes / 1024, 1);
89
+        if ($bytes < 1024) {
90
+            return "$bytes MB";
91
+        }
92
+        $bytes = round($bytes / 1024, 1);
93
+        if ($bytes < 1024) {
94
+            return "$bytes GB";
95
+        }
96
+        $bytes = round($bytes / 1024, 1);
97
+        if ($bytes < 1024) {
98
+            return "$bytes TB";
99
+        }
100
+
101
+        $bytes = round($bytes / 1024, 1);
102
+        return "$bytes PB";
103
+    }
104
+
105
+    /**
106
+     * Make a php file size
107
+     * @param int $bytes file size in bytes
108
+     * @return string a php parseable file size
109
+     *
110
+     * Makes 2048 to 2k and 2^41 to 2048G
111
+     */
112
+    public static function phpFileSize($bytes) {
113
+        if ($bytes < 0) {
114
+            return "?";
115
+        }
116
+        if ($bytes < 1024) {
117
+            return $bytes . "B";
118
+        }
119
+        $bytes = round($bytes / 1024, 1);
120
+        if ($bytes < 1024) {
121
+            return $bytes . "K";
122
+        }
123
+        $bytes = round($bytes / 1024, 1);
124
+        if ($bytes < 1024) {
125
+            return $bytes . "M";
126
+        }
127
+        $bytes = round($bytes / 1024, 1);
128
+        return $bytes . "G";
129
+    }
130
+
131
+    /**
132
+     * Make a computer file size
133
+     * @param string $str file size in human readable format
134
+     * @return float a file size in bytes
135
+     *
136
+     * Makes 2kB to 2048.
137
+     *
138
+     * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
139
+     */
140
+    public static function computerFileSize($str) {
141
+        $str = strtolower($str);
142
+        if (is_numeric($str)) {
143
+            return floatval($str);
144
+        }
145
+
146
+        $bytes_array = array(
147
+            'b' => 1,
148
+            'k' => 1024,
149
+            'kb' => 1024,
150
+            'mb' => 1024 * 1024,
151
+            'm' => 1024 * 1024,
152
+            'gb' => 1024 * 1024 * 1024,
153
+            'g' => 1024 * 1024 * 1024,
154
+            'tb' => 1024 * 1024 * 1024 * 1024,
155
+            't' => 1024 * 1024 * 1024 * 1024,
156
+            'pb' => 1024 * 1024 * 1024 * 1024 * 1024,
157
+            'p' => 1024 * 1024 * 1024 * 1024 * 1024,
158
+        );
159
+
160
+        $bytes = floatval($str);
161
+
162
+        if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) {
163
+            $bytes *= $bytes_array[$matches[1]];
164
+        } else {
165
+            return false;
166
+        }
167
+
168
+        $bytes = round($bytes);
169
+
170
+        return $bytes;
171
+    }
172
+
173
+    /**
174
+     * Recursive copying of folders
175
+     * @param string $src source folder
176
+     * @param string $dest target folder
177
+     *
178
+     */
179
+    static function copyr($src, $dest) {
180
+        if (is_dir($src)) {
181
+            if (!is_dir($dest)) {
182
+                mkdir($dest);
183
+            }
184
+            $files = scandir($src);
185
+            foreach ($files as $file) {
186
+                if ($file != "." && $file != "..") {
187
+                    self::copyr("$src/$file", "$dest/$file");
188
+                }
189
+            }
190
+        } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) {
191
+            copy($src, $dest);
192
+        }
193
+    }
194
+
195
+    /**
196
+     * Recursive deletion of folders
197
+     * @param string $dir path to the folder
198
+     * @param bool $deleteSelf if set to false only the content of the folder will be deleted
199
+     * @return bool
200
+     */
201
+    static function rmdirr($dir, $deleteSelf = true) {
202
+        if (is_dir($dir)) {
203
+            $files = new RecursiveIteratorIterator(
204
+                new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
205
+                RecursiveIteratorIterator::CHILD_FIRST
206
+            );
207
+
208
+            foreach ($files as $fileInfo) {
209
+                /** @var SplFileInfo $fileInfo */
210
+                if ($fileInfo->isLink()) {
211
+                    unlink($fileInfo->getPathname());
212
+                } else if ($fileInfo->isDir()) {
213
+                    rmdir($fileInfo->getRealPath());
214
+                } else {
215
+                    unlink($fileInfo->getRealPath());
216
+                }
217
+            }
218
+            if ($deleteSelf) {
219
+                rmdir($dir);
220
+            }
221
+        } elseif (file_exists($dir)) {
222
+            if ($deleteSelf) {
223
+                unlink($dir);
224
+            }
225
+        }
226
+        if (!$deleteSelf) {
227
+            return true;
228
+        }
229
+
230
+        return !file_exists($dir);
231
+    }
232
+
233
+    /**
234
+     * @return \OC\Files\Type\TemplateManager
235
+     */
236
+    static public function getFileTemplateManager() {
237
+        if (!self::$templateManager) {
238
+            self::$templateManager = new \OC\Files\Type\TemplateManager();
239
+        }
240
+        return self::$templateManager;
241
+    }
242
+
243
+    /**
244
+     * detect if a given program is found in the search PATH
245
+     *
246
+     * @param string $name
247
+     * @param bool $path
248
+     * @internal param string $program name
249
+     * @internal param string $optional search path, defaults to $PATH
250
+     * @return bool    true if executable program found in path
251
+     */
252
+    public static function canExecute($name, $path = false) {
253
+        // path defaults to PATH from environment if not set
254
+        if ($path === false) {
255
+            $path = getenv("PATH");
256
+        }
257
+        // we look for an executable file of that name
258
+        $exts = [""];
259
+        $check_fn = "is_executable";
260
+        // Default check will be done with $path directories :
261
+        $dirs = explode(PATH_SEPARATOR, $path);
262
+        // WARNING : We have to check if open_basedir is enabled :
263
+        $obd = OC::$server->getIniWrapper()->getString('open_basedir');
264
+        if ($obd != "none") {
265
+            $obd_values = explode(PATH_SEPARATOR, $obd);
266
+            if (count($obd_values) > 0 and $obd_values[0]) {
267
+                // open_basedir is in effect !
268
+                // We need to check if the program is in one of these dirs :
269
+                $dirs = $obd_values;
270
+            }
271
+        }
272
+        foreach ($dirs as $dir) {
273
+            foreach ($exts as $ext) {
274
+                if ($check_fn("$dir/$name" . $ext))
275
+                    return true;
276
+            }
277
+        }
278
+        return false;
279
+    }
280
+
281
+    /**
282
+     * copy the contents of one stream to another
283
+     *
284
+     * @param resource $source
285
+     * @param resource $target
286
+     * @return array the number of bytes copied and result
287
+     */
288
+    public static function streamCopy($source, $target) {
289
+        if (!$source or !$target) {
290
+            return array(0, false);
291
+        }
292
+        $bufSize = 8192;
293
+        $result = true;
294
+        $count = 0;
295
+        while (!feof($source)) {
296
+            $buf = fread($source, $bufSize);
297
+            $bytesWritten = fwrite($target, $buf);
298
+            if ($bytesWritten !== false) {
299
+                $count += $bytesWritten;
300
+            }
301
+            // note: strlen is expensive so only use it when necessary,
302
+            // on the last block
303
+            if ($bytesWritten === false
304
+                || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
305
+            ) {
306
+                // write error, could be disk full ?
307
+                $result = false;
308
+                break;
309
+            }
310
+        }
311
+        return array($count, $result);
312
+    }
313
+
314
+    /**
315
+     * Adds a suffix to the name in case the file exists
316
+     *
317
+     * @param string $path
318
+     * @param string $filename
319
+     * @return string
320
+     */
321
+    public static function buildNotExistingFileName($path, $filename) {
322
+        $view = \OC\Files\Filesystem::getView();
323
+        return self::buildNotExistingFileNameForView($path, $filename, $view);
324
+    }
325
+
326
+    /**
327
+     * Adds a suffix to the name in case the file exists
328
+     *
329
+     * @param string $path
330
+     * @param string $filename
331
+     * @return string
332
+     */
333
+    public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) {
334
+        if ($path === '/') {
335
+            $path = '';
336
+        }
337
+        if ($pos = strrpos($filename, '.')) {
338
+            $name = substr($filename, 0, $pos);
339
+            $ext = substr($filename, $pos);
340
+        } else {
341
+            $name = $filename;
342
+            $ext = '';
343
+        }
344
+
345
+        $newpath = $path . '/' . $filename;
346
+        if ($view->file_exists($newpath)) {
347
+            if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) {
348
+                //Replace the last "(number)" with "(number+1)"
349
+                $last_match = count($matches[0]) - 1;
350
+                $counter = $matches[1][$last_match][0] + 1;
351
+                $offset = $matches[0][$last_match][1];
352
+                $match_length = strlen($matches[0][$last_match][0]);
353
+            } else {
354
+                $counter = 2;
355
+                $match_length = 0;
356
+                $offset = false;
357
+            }
358
+            do {
359
+                if ($offset) {
360
+                    //Replace the last "(number)" with "(number+1)"
361
+                    $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length);
362
+                } else {
363
+                    $newname = $name . ' (' . $counter . ')';
364
+                }
365
+                $newpath = $path . '/' . $newname . $ext;
366
+                $counter++;
367
+            } while ($view->file_exists($newpath));
368
+        }
369
+
370
+        return $newpath;
371
+    }
372
+
373
+    /**
374
+     * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
375
+     *
376
+     * @param array $input The array to work on
377
+     * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
378
+     * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
379
+     * @return array
380
+     *
381
+     * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
382
+     * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715
383
+     *
384
+     */
385
+    public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
386
+        $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER;
387
+        $ret = array();
388
+        foreach ($input as $k => $v) {
389
+            $ret[mb_convert_case($k, $case, $encoding)] = $v;
390
+        }
391
+        return $ret;
392
+    }
393
+
394
+    /**
395
+     * performs a search in a nested array
396
+     * @param array $haystack the array to be searched
397
+     * @param string $needle the search string
398
+     * @param string $index optional, only search this key name
399
+     * @return mixed the key of the matching field, otherwise false
400
+     *
401
+     * performs a search in a nested array
402
+     *
403
+     * taken from http://www.php.net/manual/en/function.array-search.php#97645
404
+     */
405
+    public static function recursiveArraySearch($haystack, $needle, $index = null) {
406
+        $aIt = new RecursiveArrayIterator($haystack);
407
+        $it = new RecursiveIteratorIterator($aIt);
408
+
409
+        while ($it->valid()) {
410
+            if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) {
411
+                return $aIt->key();
412
+            }
413
+
414
+            $it->next();
415
+        }
416
+
417
+        return false;
418
+    }
419
+
420
+    /**
421
+     * calculates the maximum upload size respecting system settings, free space and user quota
422
+     *
423
+     * @param string $dir the current folder where the user currently operates
424
+     * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
425
+     * @return int number of bytes representing
426
+     */
427
+    public static function maxUploadFilesize($dir, $freeSpace = null) {
428
+        if (is_null($freeSpace) || $freeSpace < 0){
429
+            $freeSpace = self::freeSpace($dir);
430
+        }
431
+        return min($freeSpace, self::uploadLimit());
432
+    }
433
+
434
+    /**
435
+     * Calculate free space left within user quota
436
+     *
437
+     * @param string $dir the current folder where the user currently operates
438
+     * @return int number of bytes representing
439
+     */
440
+    public static function freeSpace($dir) {
441
+        $freeSpace = \OC\Files\Filesystem::free_space($dir);
442
+        if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
443
+            $freeSpace = max($freeSpace, 0);
444
+            return $freeSpace;
445
+        } else {
446
+            return (INF > 0)? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
447
+        }
448
+    }
449
+
450
+    /**
451
+     * Calculate PHP upload limit
452
+     *
453
+     * @return int PHP upload file size limit
454
+     */
455
+    public static function uploadLimit() {
456
+        $ini = \OC::$server->getIniWrapper();
457
+        $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
458
+        $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
459
+        if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
460
+            return INF;
461
+        } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
462
+            return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
463
+        } else {
464
+            return min($upload_max_filesize, $post_max_size);
465
+        }
466
+    }
467
+
468
+    /**
469
+     * Checks if a function is available
470
+     *
471
+     * @param string $function_name
472
+     * @return bool
473
+     */
474
+    public static function is_function_enabled($function_name) {
475
+        if (!function_exists($function_name)) {
476
+            return false;
477
+        }
478
+        $ini = \OC::$server->getIniWrapper();
479
+        $disabled = explode(',', $ini->get('disable_functions'));
480
+        $disabled = array_map('trim', $disabled);
481
+        if (in_array($function_name, $disabled)) {
482
+            return false;
483
+        }
484
+        $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist'));
485
+        $disabled = array_map('trim', $disabled);
486
+        if (in_array($function_name, $disabled)) {
487
+            return false;
488
+        }
489
+        return true;
490
+    }
491
+
492
+    /**
493
+     * Try to find a program
494
+     *
495
+     * @param string $program
496
+     * @return null|string
497
+     */
498
+    public static function findBinaryPath($program) {
499
+        $memcache = \OC::$server->getMemCacheFactory()->create('findBinaryPath');
500
+        if ($memcache->hasKey($program)) {
501
+            return $memcache->get($program);
502
+        }
503
+        $result = null;
504
+        if (self::is_function_enabled('exec')) {
505
+            $exeSniffer = new ExecutableFinder();
506
+            // Returns null if nothing is found
507
+            $result = $exeSniffer->find($program);
508
+            if (empty($result)) {
509
+                $paths = getenv('PATH');
510
+                if (empty($paths)) {
511
+                    $paths = '/usr/local/bin /usr/bin /opt/bin /bin';
512
+                } else {
513
+                    $paths = str_replace(':',' ',getenv('PATH'));
514
+                }
515
+                $command = 'find ' . $paths . ' -name ' . escapeshellarg($program) . ' 2> /dev/null';
516
+                exec($command, $output, $returnCode);
517
+                if (count($output) > 0) {
518
+                    $result = escapeshellcmd($output[0]);
519
+                }
520
+            }
521
+        }
522
+        // store the value for 5 minutes
523
+        $memcache->set($program, $result, 300);
524
+        return $result;
525
+    }
526
+
527
+    /**
528
+     * Calculate the disc space for the given path
529
+     *
530
+     * @param string $path
531
+     * @param \OCP\Files\FileInfo $rootInfo (optional)
532
+     * @return array
533
+     * @throws \OCP\Files\NotFoundException
534
+     */
535
+    public static function getStorageInfo($path, $rootInfo = null) {
536
+        // return storage info without adding mount points
537
+        $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
538
+
539
+        if (!$rootInfo) {
540
+            $rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage);
541
+        }
542
+        if (!$rootInfo instanceof \OCP\Files\FileInfo) {
543
+            throw new \OCP\Files\NotFoundException();
544
+        }
545
+        $used = $rootInfo->getSize();
546
+        if ($used < 0) {
547
+            $used = 0;
548
+        }
549
+        $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
550
+        $storage = $rootInfo->getStorage();
551
+        $sourceStorage = $storage;
552
+        if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
553
+            $includeExtStorage = false;
554
+            $sourceStorage = $storage->getSourceStorage();
555
+        }
556
+        if ($includeExtStorage) {
557
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
558
+                || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
559
+            ) {
560
+                /** @var \OC\Files\Storage\Home $storage */
561
+                $user = $storage->getUser();
562
+            } else {
563
+                $user = \OC::$server->getUserSession()->getUser()->getUID();
564
+            }
565
+            if ($user) {
566
+                $quota = OC_Util::getUserQuota($user);
567
+            } else {
568
+                $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
569
+            }
570
+            if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
571
+                // always get free space / total space from root + mount points
572
+                return self::getGlobalStorageInfo();
573
+            }
574
+        }
575
+
576
+        // TODO: need a better way to get total space from storage
577
+        if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
578
+            /** @var \OC\Files\Storage\Wrapper\Quota $storage */
579
+            $quota = $sourceStorage->getQuota();
580
+        }
581
+        $free = $sourceStorage->free_space($rootInfo->getInternalPath());
582
+        if ($free >= 0) {
583
+            $total = $free + $used;
584
+        } else {
585
+            $total = $free; //either unknown or unlimited
586
+        }
587
+        if ($total > 0) {
588
+            if ($quota > 0 && $total > $quota) {
589
+                $total = $quota;
590
+            }
591
+            // prevent division by zero or error codes (negative values)
592
+            $relative = round(($used / $total) * 10000) / 100;
593
+        } else {
594
+            $relative = 0;
595
+        }
596
+
597
+        $ownerId = $storage->getOwner($path);
598
+        $ownerDisplayName = '';
599
+        $owner = \OC::$server->getUserManager()->get($ownerId);
600
+        if($owner) {
601
+            $ownerDisplayName = $owner->getDisplayName();
602
+        }
603
+
604
+        return [
605
+            'free' => $free,
606
+            'used' => $used,
607
+            'quota' => $quota,
608
+            'total' => $total,
609
+            'relative' => $relative,
610
+            'owner' => $ownerId,
611
+            'ownerDisplayName' => $ownerDisplayName,
612
+        ];
613
+    }
614
+
615
+    /**
616
+     * Get storage info including all mount points and quota
617
+     *
618
+     * @return array
619
+     */
620
+    private static function getGlobalStorageInfo() {
621
+        $quota = OC_Util::getUserQuota(\OCP\User::getUser());
622
+
623
+        $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
624
+        $used = $rootInfo['size'];
625
+        if ($used < 0) {
626
+            $used = 0;
627
+        }
628
+
629
+        $total = $quota;
630
+        $free = $quota - $used;
631
+
632
+        if ($total > 0) {
633
+            if ($quota > 0 && $total > $quota) {
634
+                $total = $quota;
635
+            }
636
+            // prevent division by zero or error codes (negative values)
637
+            $relative = round(($used / $total) * 10000) / 100;
638
+        } else {
639
+            $relative = 0;
640
+        }
641
+
642
+        return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
643
+
644
+    }
645
+
646
+    /**
647
+     * Returns whether the config file is set manually to read-only
648
+     * @return bool
649
+     */
650
+    public static function isReadOnlyConfigEnabled() {
651
+        return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
652
+    }
653 653
 }
Please login to merge, or discard this patch.