helper.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Frank Karlitschek
  6. * @author Jakob Sack
  7. * @copyright 2012 Frank Karlitschek frank@owncloud.org
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public
  20. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. /**
  24. * Collection of useful functions
  25. */
  26. class OC_Helper {
  27. private static $tmpFiles = array();
  28. private static $mimetypeIcons = array();
  29. private static $mimetypeDetector;
  30. private static $templateManager;
  31. /**
  32. * Creates an url using a defined route
  33. * @param string $route
  34. * @param array $parameters
  35. * @return
  36. * @internal param array $args with param=>value, will be appended to the returned url
  37. * @return string the url
  38. *
  39. * Returns a url to the given app and file.
  40. */
  41. public static function linkToRoute($route, $parameters = array()) {
  42. return OC::$server->getURLGenerator()->linkToRoute($route, $parameters);
  43. }
  44. /**
  45. * Creates an url
  46. * @param string $app app
  47. * @param string $file file
  48. * @param array $args array with param=>value, will be appended to the returned url
  49. * The value of $args will be urlencoded
  50. * @return string the url
  51. *
  52. * Returns a url to the given app and file.
  53. */
  54. public static function linkTo( $app, $file, $args = array() ) {
  55. return OC::$server->getURLGenerator()->linkTo($app, $file, $args);
  56. }
  57. /**
  58. * @param $key
  59. * @return string url to the online documentation
  60. */
  61. public static function linkToDocs($key) {
  62. $theme = new OC_Defaults();
  63. return $theme->buildDocLinkToKey($key);
  64. }
  65. /**
  66. * Creates an absolute url
  67. * @param string $app app
  68. * @param string $file file
  69. * @param array $args array with param=>value, will be appended to the returned url
  70. * The value of $args will be urlencoded
  71. * @return string the url
  72. *
  73. * Returns a absolute url to the given app and file.
  74. */
  75. public static function linkToAbsolute($app, $file, $args = array()) {
  76. return OC::$server->getURLGenerator()->getAbsoluteURL(
  77. self::linkTo($app, $file, $args)
  78. );
  79. }
  80. /**
  81. * Makes an $url absolute
  82. * @param string $url the url
  83. * @return string the absolute url
  84. *
  85. * Returns a absolute url to the given app and file.
  86. */
  87. public static function makeURLAbsolute($url) {
  88. return OC::$server->getURLGenerator()->getAbsoluteURL($url);
  89. }
  90. /**
  91. * Creates an url for remote use
  92. * @param string $service id
  93. * @return string the url
  94. *
  95. * Returns a url to the given service.
  96. */
  97. public static function linkToRemoteBase($service) {
  98. return self::linkTo('', 'remote.php') . '/' . $service;
  99. }
  100. /**
  101. * Creates an absolute url for remote use
  102. * @param string $service id
  103. * @param bool $add_slash
  104. * @return string the url
  105. *
  106. * Returns a absolute url to the given service.
  107. */
  108. public static function linkToRemote($service, $add_slash = true) {
  109. return OC::$server->getURLGenerator()->getAbsoluteURL(
  110. self::linkToRemoteBase($service)
  111. . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '')
  112. );
  113. }
  114. /**
  115. * Creates an absolute url for public use
  116. * @param string $service id
  117. * @param bool $add_slash
  118. * @return string the url
  119. *
  120. * Returns a absolute url to the given service.
  121. */
  122. public static function linkToPublic($service, $add_slash = false) {
  123. return OC::$server->getURLGenerator()->getAbsoluteURL(
  124. self::linkTo(
  125. '', 'public.php') . '?service=' . $service
  126. . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''
  127. )
  128. );
  129. }
  130. /**
  131. * Creates path to an image
  132. * @param string $app app
  133. * @param string $image image name
  134. * @return string the url
  135. *
  136. * Returns the path to the image.
  137. */
  138. public static function imagePath($app, $image) {
  139. return OC::$server->getURLGenerator()->imagePath($app, $image);
  140. }
  141. /**
  142. * get path to icon of file type
  143. * @param string $mimetype mimetype
  144. * @return string the url
  145. *
  146. * Returns the path to the image of this file type.
  147. */
  148. public static function mimetypeIcon($mimetype) {
  149. $alias = array(
  150. 'application/octet-stream' => 'file', // use file icon as fallback
  151. 'application/illustrator' => 'image',
  152. 'application/coreldraw' => 'image',
  153. 'application/x-gimp' => 'image',
  154. 'application/x-photoshop' => 'image',
  155. 'application/x-font-ttf' => 'font',
  156. 'application/font-woff' => 'font',
  157. 'application/vnd.ms-fontobject' => 'font',
  158. 'application/json' => 'text/code',
  159. 'application/x-perl' => 'text/code',
  160. 'application/x-php' => 'text/code',
  161. 'text/x-shellscript' => 'text/code',
  162. 'application/xml' => 'text/html',
  163. 'text/css' => 'text/code',
  164. 'application/x-tex' => 'text',
  165. 'application/x-compressed' => 'package/x-generic',
  166. 'application/x-7z-compressed' => 'package/x-generic',
  167. 'application/x-deb' => 'package/x-generic',
  168. 'application/x-gzip' => 'package/x-generic',
  169. 'application/x-rar-compressed' => 'package/x-generic',
  170. 'application/x-tar' => 'package/x-generic',
  171. 'application/zip' => 'package/x-generic',
  172. 'application/msword' => 'x-office/document',
  173. 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document',
  174. 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document',
  175. 'application/vnd.ms-word.document.macroEnabled.12' => 'x-office/document',
  176. 'application/vnd.ms-word.template.macroEnabled.12' => 'x-office/document',
  177. 'application/vnd.oasis.opendocument.text' => 'x-office/document',
  178. 'application/vnd.oasis.opendocument.text-template' => 'x-office/document',
  179. 'application/vnd.oasis.opendocument.text-web' => 'x-office/document',
  180. 'application/vnd.oasis.opendocument.text-master' => 'x-office/document',
  181. 'application/mspowerpoint' => 'x-office/presentation',
  182. 'application/vnd.ms-powerpoint' => 'x-office/presentation',
  183. 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation',
  184. 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation',
  185. 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'x-office/presentation',
  186. 'application/vnd.ms-powerpoint.addin.macroEnabled.12' => 'x-office/presentation',
  187. 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' => 'x-office/presentation',
  188. 'application/vnd.ms-powerpoint.template.macroEnabled.12' => 'x-office/presentation',
  189. 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation',
  190. 'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation',
  191. 'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation',
  192. 'application/msexcel' => 'x-office/spreadsheet',
  193. 'application/vnd.ms-excel' => 'x-office/spreadsheet',
  194. 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet',
  195. 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet',
  196. 'application/vnd.ms-excel.sheet.macroEnabled.12' => 'x-office/spreadsheet',
  197. 'application/vnd.ms-excel.template.macroEnabled.12' => 'x-office/spreadsheet',
  198. 'application/vnd.ms-excel.addin.macroEnabled.12' => 'x-office/spreadsheet',
  199. 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet',
  200. 'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet',
  201. 'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet',
  202. 'text/csv' => 'x-office/spreadsheet',
  203. 'application/msaccess' => 'database',
  204. );
  205. if (isset($alias[$mimetype])) {
  206. $mimetype = $alias[$mimetype];
  207. }
  208. if (isset(self::$mimetypeIcons[$mimetype])) {
  209. return self::$mimetypeIcons[$mimetype];
  210. }
  211. // Replace slash and backslash with a minus
  212. $icon = str_replace('/', '-', $mimetype);
  213. $icon = str_replace('\\', '-', $icon);
  214. // Is it a dir?
  215. if ($mimetype === 'dir') {
  216. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder.png';
  217. return OC::$WEBROOT . '/core/img/filetypes/folder.png';
  218. }
  219. if ($mimetype === 'dir-shared') {
  220. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-shared.png';
  221. return OC::$WEBROOT . '/core/img/filetypes/folder-shared.png';
  222. }
  223. if ($mimetype === 'dir-external') {
  224. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-external.png';
  225. return OC::$WEBROOT . '/core/img/filetypes/folder-external.png';
  226. }
  227. // Icon exists?
  228. if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $icon . '.png')) {
  229. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png';
  230. return OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png';
  231. }
  232. // Try only the first part of the filetype
  233. $mimePart = substr($icon, 0, strpos($icon, '-'));
  234. if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $mimePart . '.png')) {
  235. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png';
  236. return OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png';
  237. } else {
  238. self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/file.png';
  239. return OC::$WEBROOT . '/core/img/filetypes/file.png';
  240. }
  241. }
  242. /**
  243. * get path to preview of file
  244. * @param string $path path
  245. * @return string the url
  246. *
  247. * Returns the path to the preview of the file.
  248. */
  249. public static function previewIcon($path) {
  250. return self::linkToRoute( 'core_ajax_preview', array('x' => 36, 'y' => 36, 'file' => $path ));
  251. }
  252. public static function publicPreviewIcon( $path, $token ) {
  253. return self::linkToRoute( 'core_ajax_public_preview', array('x' => 36, 'y' => 36, 'file' => $path, 't' => $token));
  254. }
  255. /**
  256. * Make a human file size
  257. * @param int $bytes file size in bytes
  258. * @return string a human readable file size
  259. *
  260. * Makes 2048 to 2 kB.
  261. */
  262. public static function humanFileSize($bytes) {
  263. if ($bytes < 0) {
  264. return "?";
  265. }
  266. if ($bytes < 1024) {
  267. return "$bytes B";
  268. }
  269. $bytes = round($bytes / 1024, 0);
  270. if ($bytes < 1024) {
  271. return "$bytes kB";
  272. }
  273. $bytes = round($bytes / 1024, 1);
  274. if ($bytes < 1024) {
  275. return "$bytes MB";
  276. }
  277. $bytes = round($bytes / 1024, 1);
  278. if ($bytes < 1024) {
  279. return "$bytes GB";
  280. }
  281. $bytes = round($bytes / 1024, 1);
  282. if ($bytes < 1024) {
  283. return "$bytes TB";
  284. }
  285. $bytes = round($bytes / 1024, 1);
  286. return "$bytes PB";
  287. }
  288. /**
  289. * Make a php file size
  290. * @param int $bytes file size in bytes
  291. * @return string a php parseable file size
  292. *
  293. * Makes 2048 to 2k and 2^41 to 2048G
  294. */
  295. public static function phpFileSize($bytes) {
  296. if ($bytes < 0) {
  297. return "?";
  298. }
  299. if ($bytes < 1024) {
  300. return $bytes . "B";
  301. }
  302. $bytes = round($bytes / 1024, 1);
  303. if ($bytes < 1024) {
  304. return $bytes . "K";
  305. }
  306. $bytes = round($bytes / 1024, 1);
  307. if ($bytes < 1024) {
  308. return $bytes . "M";
  309. }
  310. $bytes = round($bytes / 1024, 1);
  311. return $bytes . "G";
  312. }
  313. /**
  314. * Make a computer file size
  315. * @param string $str file size in human readable format
  316. * @return int a file size in bytes
  317. *
  318. * Makes 2kB to 2048.
  319. *
  320. * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
  321. */
  322. public static function computerFileSize($str) {
  323. $str = strtolower($str);
  324. $bytes_array = array(
  325. 'b' => 1,
  326. 'k' => 1024,
  327. 'kb' => 1024,
  328. 'mb' => 1024 * 1024,
  329. 'm' => 1024 * 1024,
  330. 'gb' => 1024 * 1024 * 1024,
  331. 'g' => 1024 * 1024 * 1024,
  332. 'tb' => 1024 * 1024 * 1024 * 1024,
  333. 't' => 1024 * 1024 * 1024 * 1024,
  334. 'pb' => 1024 * 1024 * 1024 * 1024 * 1024,
  335. 'p' => 1024 * 1024 * 1024 * 1024 * 1024,
  336. );
  337. $bytes = floatval($str);
  338. if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) {
  339. $bytes *= $bytes_array[$matches[1]];
  340. }
  341. $bytes = round($bytes);
  342. return $bytes;
  343. }
  344. /**
  345. * Recursive copying of folders
  346. * @param string $src source folder
  347. * @param string $dest target folder
  348. *
  349. */
  350. static function copyr($src, $dest) {
  351. if (is_dir($src)) {
  352. if (!is_dir($dest)) {
  353. mkdir($dest);
  354. }
  355. $files = scandir($src);
  356. foreach ($files as $file) {
  357. if ($file != "." && $file != "..") {
  358. self::copyr("$src/$file", "$dest/$file");
  359. }
  360. }
  361. } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) {
  362. copy($src, $dest);
  363. }
  364. }
  365. /**
  366. * Recursive deletion of folders
  367. * @param string $dir path to the folder
  368. * @return bool
  369. */
  370. static function rmdirr($dir) {
  371. if (is_dir($dir)) {
  372. $files = new RecursiveIteratorIterator(
  373. new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
  374. RecursiveIteratorIterator::CHILD_FIRST
  375. );
  376. foreach ($files as $fileInfo) {
  377. /** @var SplFileInfo $fileInfo */
  378. if ($fileInfo->isDir()) {
  379. rmdir($fileInfo->getRealPath());
  380. } else {
  381. unlink($fileInfo->getRealPath());
  382. }
  383. }
  384. rmdir($dir);
  385. } elseif (file_exists($dir)) {
  386. unlink($dir);
  387. }
  388. if (file_exists($dir)) {
  389. return false;
  390. } else {
  391. return true;
  392. }
  393. }
  394. /**
  395. * @return \OC\Files\Type\Detection
  396. */
  397. static public function getMimetypeDetector() {
  398. if (!self::$mimetypeDetector) {
  399. self::$mimetypeDetector = new \OC\Files\Type\Detection();
  400. self::$mimetypeDetector->registerTypeArray(include 'mimetypes.list.php');
  401. }
  402. return self::$mimetypeDetector;
  403. }
  404. /**
  405. * @return \OC\Files\Type\TemplateManager
  406. */
  407. static public function getFileTemplateManager() {
  408. if (!self::$templateManager) {
  409. self::$templateManager = new \OC\Files\Type\TemplateManager();
  410. }
  411. return self::$templateManager;
  412. }
  413. /**
  414. * Try to guess the mimetype based on filename
  415. *
  416. * @param string $path
  417. * @return string
  418. */
  419. static public function getFileNameMimeType($path) {
  420. return self::getMimetypeDetector()->detectPath($path);
  421. }
  422. /**
  423. * get the mimetype form a local file
  424. *
  425. * @param string $path
  426. * @return string
  427. * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
  428. */
  429. static function getMimeType($path) {
  430. return self::getMimetypeDetector()->detect($path);
  431. }
  432. /**
  433. * Get a secure mimetype that won't expose potential XSS.
  434. *
  435. * @param string $mimeType
  436. * @return string
  437. */
  438. static function getSecureMimeType($mimeType) {
  439. return self::getMimetypeDetector()->getSecureMimeType($mimeType);
  440. }
  441. /**
  442. * get the mimetype form a data string
  443. *
  444. * @param string $data
  445. * @return string
  446. */
  447. static function getStringMimeType($data) {
  448. return self::getMimetypeDetector()->detectString($data);
  449. }
  450. /**
  451. * Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d.
  452. * @param string $s name of the var to escape, if set.
  453. * @param string $d default value.
  454. * @return string the print-safe value.
  455. *
  456. */
  457. /**
  458. * detect if a given program is found in the search PATH
  459. *
  460. * @param string $name
  461. * @param bool $path
  462. * @internal param string $program name
  463. * @internal param string $optional search path, defaults to $PATH
  464. * @return bool true if executable program found in path
  465. */
  466. public static function canExecute($name, $path = false) {
  467. // path defaults to PATH from environment if not set
  468. if ($path === false) {
  469. $path = getenv("PATH");
  470. }
  471. // check method depends on operating system
  472. if (!strncmp(PHP_OS, "WIN", 3)) {
  473. // on Windows an appropriate COM or EXE file needs to exist
  474. $exts = array(".exe", ".com");
  475. $check_fn = "file_exists";
  476. } else {
  477. // anywhere else we look for an executable file of that name
  478. $exts = array("");
  479. $check_fn = "is_executable";
  480. }
  481. // Default check will be done with $path directories :
  482. $dirs = explode(PATH_SEPARATOR, $path);
  483. // WARNING : We have to check if open_basedir is enabled :
  484. $obd = ini_get('open_basedir');
  485. if ($obd != "none") {
  486. $obd_values = explode(PATH_SEPARATOR, $obd);
  487. if (count($obd_values) > 0 and $obd_values[0]) {
  488. // open_basedir is in effect !
  489. // We need to check if the program is in one of these dirs :
  490. $dirs = $obd_values;
  491. }
  492. }
  493. foreach ($dirs as $dir) {
  494. foreach ($exts as $ext) {
  495. if ($check_fn("$dir/$name" . $ext))
  496. return true;
  497. }
  498. }
  499. return false;
  500. }
  501. /**
  502. * copy the contents of one stream to another
  503. *
  504. * @param resource $source
  505. * @param resource $target
  506. * @return array the number of bytes copied and result
  507. */
  508. public static function streamCopy($source, $target) {
  509. if (!$source or !$target) {
  510. return array(0, false);
  511. }
  512. $result = true;
  513. $count = 0;
  514. while (!feof($source)) {
  515. if (($c = fwrite($target, fread($source, 8192))) === false) {
  516. $result = false;
  517. } else {
  518. $count += $c;
  519. }
  520. }
  521. return array($count, $result);
  522. }
  523. /**
  524. * create a temporary file with an unique filename
  525. *
  526. * @param string $postfix
  527. * @return string
  528. *
  529. * temporary files are automatically cleaned up after the script is finished
  530. */
  531. public static function tmpFile($postfix = '') {
  532. $file = get_temp_dir() . '/' . md5(time() . rand()) . $postfix;
  533. $fh = fopen($file, 'w');
  534. fclose($fh);
  535. self::$tmpFiles[] = $file;
  536. return $file;
  537. }
  538. /**
  539. * move a file to oc-noclean temp dir
  540. *
  541. * @param string $filename
  542. * @return mixed
  543. *
  544. */
  545. public static function moveToNoClean($filename = '') {
  546. if ($filename == '') {
  547. return false;
  548. }
  549. $tmpDirNoClean = get_temp_dir() . '/oc-noclean/';
  550. if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) {
  551. if (file_exists($tmpDirNoClean)) {
  552. unlink($tmpDirNoClean);
  553. }
  554. mkdir($tmpDirNoClean);
  555. }
  556. $newname = $tmpDirNoClean . basename($filename);
  557. if (rename($filename, $newname)) {
  558. return $newname;
  559. } else {
  560. return false;
  561. }
  562. }
  563. /**
  564. * create a temporary folder with an unique filename
  565. *
  566. * @return string
  567. *
  568. * temporary files are automatically cleaned up after the script is finished
  569. */
  570. public static function tmpFolder() {
  571. $path = get_temp_dir() . '/' . md5(time() . rand());
  572. mkdir($path);
  573. self::$tmpFiles[] = $path;
  574. return $path . '/';
  575. }
  576. /**
  577. * remove all files created by self::tmpFile
  578. */
  579. public static function cleanTmp() {
  580. $leftoversFile = get_temp_dir() . '/oc-not-deleted';
  581. if (file_exists($leftoversFile)) {
  582. $leftovers = file($leftoversFile);
  583. foreach ($leftovers as $file) {
  584. self::rmdirr($file);
  585. }
  586. unlink($leftoversFile);
  587. }
  588. foreach (self::$tmpFiles as $file) {
  589. if (file_exists($file)) {
  590. if (!self::rmdirr($file)) {
  591. file_put_contents($leftoversFile, $file . "\n", FILE_APPEND);
  592. }
  593. }
  594. }
  595. }
  596. /**
  597. * remove all files in PHP /oc-noclean temp dir
  598. */
  599. public static function cleanTmpNoClean() {
  600. $tmpDirNoCleanName=get_temp_dir() . '/oc-noclean/';
  601. if(file_exists($tmpDirNoCleanName) && is_dir($tmpDirNoCleanName)) {
  602. $files=scandir($tmpDirNoCleanName);
  603. foreach($files as $file) {
  604. $fileName = $tmpDirNoCleanName . $file;
  605. if (!\OC\Files\Filesystem::isIgnoredDir($file) && filemtime($fileName) + 600 < time()) {
  606. unlink($fileName);
  607. }
  608. }
  609. // if oc-noclean is empty delete it
  610. $isTmpDirNoCleanEmpty = true;
  611. $tmpDirNoClean = opendir($tmpDirNoCleanName);
  612. if(is_resource($tmpDirNoClean)) {
  613. while (false !== ($file = readdir($tmpDirNoClean))) {
  614. if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
  615. $isTmpDirNoCleanEmpty = false;
  616. }
  617. }
  618. }
  619. if ($isTmpDirNoCleanEmpty) {
  620. rmdir($tmpDirNoCleanName);
  621. }
  622. }
  623. }
  624. /**
  625. * Adds a suffix to the name in case the file exists
  626. *
  627. * @param string $path
  628. * @param string $filename
  629. * @return string
  630. */
  631. public static function buildNotExistingFileName($path, $filename) {
  632. $view = \OC\Files\Filesystem::getView();
  633. return self::buildNotExistingFileNameForView($path, $filename, $view);
  634. }
  635. /**
  636. * Adds a suffix to the name in case the file exists
  637. *
  638. * @param string $path
  639. * @param string $filename
  640. * @return string
  641. */
  642. public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) {
  643. if ($path === '/') {
  644. $path = '';
  645. }
  646. if ($pos = strrpos($filename, '.')) {
  647. $name = substr($filename, 0, $pos);
  648. $ext = substr($filename, $pos);
  649. } else {
  650. $name = $filename;
  651. $ext = '';
  652. }
  653. $newpath = $path . '/' . $filename;
  654. if ($view->file_exists($newpath)) {
  655. if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) {
  656. //Replace the last "(number)" with "(number+1)"
  657. $last_match = count($matches[0]) - 1;
  658. $counter = $matches[1][$last_match][0] + 1;
  659. $offset = $matches[0][$last_match][1];
  660. $match_length = strlen($matches[0][$last_match][0]);
  661. } else {
  662. $counter = 2;
  663. $offset = false;
  664. }
  665. do {
  666. if ($offset) {
  667. //Replace the last "(number)" with "(number+1)"
  668. $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length);
  669. } else {
  670. $newname = $name . ' (' . $counter . ')';
  671. }
  672. $newpath = $path . '/' . $newname . $ext;
  673. $counter++;
  674. } while ($view->file_exists($newpath));
  675. }
  676. return $newpath;
  677. }
  678. /**
  679. * Checks if $sub is a subdirectory of $parent
  680. *
  681. * @param string $sub
  682. * @param string $parent
  683. * @return bool
  684. */
  685. public static function isSubDirectory($sub, $parent) {
  686. $realpathSub = realpath($sub);
  687. $realpathParent = realpath($parent);
  688. // realpath() may return false in case the directory does not exist
  689. // since we can not be sure how different PHP versions may behave here
  690. // we do an additional check whether realpath returned false
  691. if($realpathSub === false || $realpathParent === false) {
  692. return false;
  693. }
  694. // Check whether $sub is a subdirectory of $parent
  695. if (strpos($realpathSub, $realpathParent) === 0) {
  696. return true;
  697. }
  698. return false;
  699. }
  700. /**
  701. * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
  702. *
  703. * @param array $input The array to work on
  704. * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
  705. * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
  706. * @return array
  707. *
  708. * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
  709. * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715
  710. *
  711. */
  712. public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
  713. $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER;
  714. $ret = array();
  715. foreach ($input as $k => $v) {
  716. $ret[mb_convert_case($k, $case, $encoding)] = $v;
  717. }
  718. return $ret;
  719. }
  720. /**
  721. * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement.
  722. *
  723. * @param string $string
  724. * @param string $replacement The replacement string.
  725. * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string.
  726. * @param int $length Length of the part to be replaced
  727. * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
  728. * @internal param string $input The input string. .Opposite to the PHP build-in function does not accept an array.
  729. * @return string
  730. */
  731. public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') {
  732. $start = intval($start);
  733. $length = intval($length);
  734. $string = mb_substr($string, 0, $start, $encoding) .
  735. $replacement .
  736. mb_substr($string, $start + $length, mb_strlen($string, 'UTF-8') - $start, $encoding);
  737. return $string;
  738. }
  739. /**
  740. * Replace all occurrences of the search string with the replacement string
  741. *
  742. * @param string $search The value being searched for, otherwise known as the needle.
  743. * @param string $replace The replacement
  744. * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack.
  745. * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
  746. * @param int $count If passed, this will be set to the number of replacements performed.
  747. * @return string
  748. *
  749. */
  750. public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) {
  751. $offset = -1;
  752. $length = mb_strlen($search, $encoding);
  753. while (($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false) {
  754. $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length);
  755. $offset = $i - mb_strlen($subject, $encoding);
  756. $count++;
  757. }
  758. return $subject;
  759. }
  760. /**
  761. * performs a search in a nested array
  762. * @param array $haystack the array to be searched
  763. * @param string $needle the search string
  764. * @param string $index optional, only search this key name
  765. * @return mixed the key of the matching field, otherwise false
  766. *
  767. * performs a search in a nested array
  768. *
  769. * taken from http://www.php.net/manual/en/function.array-search.php#97645
  770. */
  771. public static function recursiveArraySearch($haystack, $needle, $index = null) {
  772. $aIt = new RecursiveArrayIterator($haystack);
  773. $it = new RecursiveIteratorIterator($aIt);
  774. while ($it->valid()) {
  775. if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) {
  776. return $aIt->key();
  777. }
  778. $it->next();
  779. }
  780. return false;
  781. }
  782. /**
  783. * Shortens str to maxlen by replacing characters in the middle with '...', eg.
  784. * ellipsis('a very long string with lots of useless info to make a better example', 14) becomes 'a very ...example'
  785. *
  786. * @param string $str the string
  787. * @param string $maxlen the maximum length of the result
  788. * @return string with at most maxlen characters
  789. */
  790. public static function ellipsis($str, $maxlen) {
  791. if (strlen($str) > $maxlen) {
  792. $characters = floor($maxlen / 2);
  793. return substr($str, 0, $characters) . '...' . substr($str, -1 * $characters);
  794. }
  795. return $str;
  796. }
  797. /**
  798. * calculates the maximum upload size respecting system settings, free space and user quota
  799. *
  800. * @param string $dir the current folder where the user currently operates
  801. * @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
  802. * @return int number of bytes representing
  803. */
  804. public static function maxUploadFilesize($dir, $freeSpace = null) {
  805. if (is_null($freeSpace) || $freeSpace < 0){
  806. $freeSpace = self::freeSpace($dir);
  807. }
  808. return min($freeSpace, self::uploadLimit());
  809. }
  810. /**
  811. * Calculate free space left within user quota
  812. *
  813. * @param string $dir the current folder where the user currently operates
  814. * @return int number of bytes representing
  815. */
  816. public static function freeSpace($dir) {
  817. $freeSpace = \OC\Files\Filesystem::free_space($dir);
  818. if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) {
  819. $freeSpace = max($freeSpace, 0);
  820. return $freeSpace;
  821. } else {
  822. return INF;
  823. }
  824. }
  825. /**
  826. * Calculate PHP upload limit
  827. *
  828. * @return PHP upload file size limit
  829. */
  830. public static function uploadLimit() {
  831. $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
  832. $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
  833. if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
  834. return INF;
  835. } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
  836. return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
  837. } else {
  838. return min($upload_max_filesize, $post_max_size);
  839. }
  840. }
  841. /**
  842. * Checks if a function is available
  843. *
  844. * @param string $function_name
  845. * @return bool
  846. */
  847. public static function is_function_enabled($function_name) {
  848. if (!function_exists($function_name)) {
  849. return false;
  850. }
  851. $disabled = explode(',', ini_get('disable_functions'));
  852. $disabled = array_map('trim', $disabled);
  853. if (in_array($function_name, $disabled)) {
  854. return false;
  855. }
  856. $disabled = explode(',', ini_get('suhosin.executor.func.blacklist'));
  857. $disabled = array_map('trim', $disabled);
  858. if (in_array($function_name, $disabled)) {
  859. return false;
  860. }
  861. return true;
  862. }
  863. /**
  864. * Calculate the disc space for the given path
  865. *
  866. * @param string $path
  867. * @param \OCP\Files\FileInfo $rootInfo (optional)
  868. * @return array
  869. */
  870. public static function getStorageInfo($path, $rootInfo = null) {
  871. // return storage info without adding mount points
  872. $includeExtStorage = \OC_Config::getValue('quota_include_external_storage', false);
  873. if (!$rootInfo) {
  874. $rootInfo = \OC\Files\Filesystem::getFileInfo($path, false);
  875. }
  876. $used = $rootInfo->getSize();
  877. if ($used < 0) {
  878. $used = 0;
  879. }
  880. $quota = 0;
  881. $storage = $rootInfo->getStorage();
  882. if ($includeExtStorage && $storage->instanceOfStorage('\OC\Files\Storage\Shared')) {
  883. $includeExtStorage = false;
  884. }
  885. if ($includeExtStorage) {
  886. $quota = OC_Util::getUserQuota(\OCP\User::getUser());
  887. if ($quota !== \OC\Files\SPACE_UNLIMITED) {
  888. // always get free space / total space from root + mount points
  889. $path = '';
  890. return self::getGlobalStorageInfo();
  891. }
  892. }
  893. // TODO: need a better way to get total space from storage
  894. if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) {
  895. $quota = $storage->getQuota();
  896. }
  897. $free = $storage->free_space('');
  898. if ($free >= 0) {
  899. $total = $free + $used;
  900. } else {
  901. $total = $free; //either unknown or unlimited
  902. }
  903. if ($total > 0) {
  904. if ($quota > 0 && $total > $quota) {
  905. $total = $quota;
  906. }
  907. // prevent division by zero or error codes (negative values)
  908. $relative = round(($used / $total) * 10000) / 100;
  909. } else {
  910. $relative = 0;
  911. }
  912. return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
  913. }
  914. /**
  915. * Get storage info including all mount points and quota
  916. *
  917. * @return array
  918. */
  919. private static function getGlobalStorageInfo() {
  920. $quota = OC_Util::getUserQuota(\OCP\User::getUser());
  921. $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
  922. $used = $rootInfo['size'];
  923. if ($used < 0) {
  924. $used = 0;
  925. }
  926. $total = $quota;
  927. $free = $quota - $used;
  928. if ($total > 0) {
  929. if ($quota > 0 && $total > $quota) {
  930. $total = $quota;
  931. }
  932. // prevent division by zero or error codes (negative values)
  933. $relative = round(($used / $total) * 10000) / 100;
  934. } else {
  935. $relative = 0;
  936. }
  937. return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative);
  938. }
  939. }