Completed
Pull Request — master (#6549)
by Blizzz
22:10 queued 06:49
created
lib/private/legacy/helper.php 1 patch
Indentation   +603 added lines, -603 removed lines patch added patch discarded remove patch
@@ -48,607 +48,607 @@
 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|bool 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 mixed $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 ? 'ext' : false);
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
-				$userInstance = $storage->getUser();
562
-				$user = ($userInstance === null) ? null : $userInstance->getUID();
563
-			} else {
564
-				$user = \OC::$server->getUserSession()->getUser()->getUID();
565
-			}
566
-			if ($user) {
567
-				$quota = OC_Util::getUserQuota($user);
568
-			} else {
569
-				$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
570
-			}
571
-			if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
572
-				// always get free space / total space from root + mount points
573
-				return self::getGlobalStorageInfo();
574
-			}
575
-		}
576
-
577
-		// TODO: need a better way to get total space from storage
578
-		if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
579
-			/** @var \OC\Files\Storage\Wrapper\Quota $storage */
580
-			$quota = $sourceStorage->getQuota();
581
-		}
582
-		$free = $sourceStorage->free_space($rootInfo->getInternalPath());
583
-		if ($free >= 0) {
584
-			$total = $free + $used;
585
-		} else {
586
-			$total = $free; //either unknown or unlimited
587
-		}
588
-		if ($total > 0) {
589
-			if ($quota > 0 && $total > $quota) {
590
-				$total = $quota;
591
-			}
592
-			// prevent division by zero or error codes (negative values)
593
-			$relative = round(($used / $total) * 10000) / 100;
594
-		} else {
595
-			$relative = 0;
596
-		}
597
-
598
-		$ownerId = $storage->getOwner($path);
599
-		$ownerDisplayName = '';
600
-		$owner = \OC::$server->getUserManager()->get($ownerId);
601
-		if($owner) {
602
-			$ownerDisplayName = $owner->getDisplayName();
603
-		}
604
-
605
-		return [
606
-			'free' => $free,
607
-			'used' => $used,
608
-			'quota' => $quota,
609
-			'total' => $total,
610
-			'relative' => $relative,
611
-			'owner' => $ownerId,
612
-			'ownerDisplayName' => $ownerDisplayName,
613
-		];
614
-	}
615
-
616
-	/**
617
-	 * Get storage info including all mount points and quota
618
-	 *
619
-	 * @return array
620
-	 */
621
-	private static function getGlobalStorageInfo() {
622
-		$quota = OC_Util::getUserQuota(\OCP\User::getUser());
623
-
624
-		$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
625
-		$used = $rootInfo['size'];
626
-		if ($used < 0) {
627
-			$used = 0;
628
-		}
629
-
630
-		$total = $quota;
631
-		$free = $quota - $used;
632
-
633
-		if ($total > 0) {
634
-			if ($quota > 0 && $total > $quota) {
635
-				$total = $quota;
636
-			}
637
-			// prevent division by zero or error codes (negative values)
638
-			$relative = round(($used / $total) * 10000) / 100;
639
-		} else {
640
-			$relative = 0;
641
-		}
642
-
643
-		return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
644
-
645
-	}
646
-
647
-	/**
648
-	 * Returns whether the config file is set manually to read-only
649
-	 * @return bool
650
-	 */
651
-	public static function isReadOnlyConfigEnabled() {
652
-		return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
653
-	}
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|bool 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 mixed $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 ? 'ext' : false);
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
+                $userInstance = $storage->getUser();
562
+                $user = ($userInstance === null) ? null : $userInstance->getUID();
563
+            } else {
564
+                $user = \OC::$server->getUserSession()->getUser()->getUID();
565
+            }
566
+            if ($user) {
567
+                $quota = OC_Util::getUserQuota($user);
568
+            } else {
569
+                $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
570
+            }
571
+            if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
572
+                // always get free space / total space from root + mount points
573
+                return self::getGlobalStorageInfo();
574
+            }
575
+        }
576
+
577
+        // TODO: need a better way to get total space from storage
578
+        if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
579
+            /** @var \OC\Files\Storage\Wrapper\Quota $storage */
580
+            $quota = $sourceStorage->getQuota();
581
+        }
582
+        $free = $sourceStorage->free_space($rootInfo->getInternalPath());
583
+        if ($free >= 0) {
584
+            $total = $free + $used;
585
+        } else {
586
+            $total = $free; //either unknown or unlimited
587
+        }
588
+        if ($total > 0) {
589
+            if ($quota > 0 && $total > $quota) {
590
+                $total = $quota;
591
+            }
592
+            // prevent division by zero or error codes (negative values)
593
+            $relative = round(($used / $total) * 10000) / 100;
594
+        } else {
595
+            $relative = 0;
596
+        }
597
+
598
+        $ownerId = $storage->getOwner($path);
599
+        $ownerDisplayName = '';
600
+        $owner = \OC::$server->getUserManager()->get($ownerId);
601
+        if($owner) {
602
+            $ownerDisplayName = $owner->getDisplayName();
603
+        }
604
+
605
+        return [
606
+            'free' => $free,
607
+            'used' => $used,
608
+            'quota' => $quota,
609
+            'total' => $total,
610
+            'relative' => $relative,
611
+            'owner' => $ownerId,
612
+            'ownerDisplayName' => $ownerDisplayName,
613
+        ];
614
+    }
615
+
616
+    /**
617
+     * Get storage info including all mount points and quota
618
+     *
619
+     * @return array
620
+     */
621
+    private static function getGlobalStorageInfo() {
622
+        $quota = OC_Util::getUserQuota(\OCP\User::getUser());
623
+
624
+        $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
625
+        $used = $rootInfo['size'];
626
+        if ($used < 0) {
627
+            $used = 0;
628
+        }
629
+
630
+        $total = $quota;
631
+        $free = $quota - $used;
632
+
633
+        if ($total > 0) {
634
+            if ($quota > 0 && $total > $quota) {
635
+                $total = $quota;
636
+            }
637
+            // prevent division by zero or error codes (negative values)
638
+            $relative = round(($used / $total) * 10000) / 100;
639
+        } else {
640
+            $relative = 0;
641
+        }
642
+
643
+        return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
644
+
645
+    }
646
+
647
+    /**
648
+     * Returns whether the config file is set manually to read-only
649
+     * @return bool
650
+     */
651
+    public static function isReadOnlyConfigEnabled() {
652
+        return \OC::$server->getConfig()->getSystemValue('config_is_read_only', false);
653
+    }
654 654
 }
Please login to merge, or discard this patch.